Hello there, fellow coders! Are you tired of browsing through endless memes and want to try your hand at creating your own? Look no further, because in this blog post, we are going to create a custom Meme Generator using the power of JavaScript! With the help of HTML, CSS, and some JavaScript magic, we’ll create a tool that will allow you to upload your own images, add text captions, and generate hilarious memes in no time. Not only will this project be a fun and creative endeavor, but you’ll also gain valuable experience in web development, including working with images, user input, and dynamic content generation. So let’s roll up our sleeves and get started on creating your very own Meme Generator!
Before we start here are some more projects you might like to create –
- 3D CSS Logo with Pure CSS
- 3D Santa using HTML and CSS Only
- Crafting a 3D Police Squad Car with Pure CSS
- Crafting a 3D Printer with HTML and Pure CSS
- Building a Pure CSS 3D Kitchen
I would recommend you don’t just copy and paste the code, just look at the code and type by understanding it.
HTML Code
Starter Template
<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <!-- Font Awesome Icons --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA==" crossorigin="anonymous" /> <!-- CSS --> <link rel="stylesheet" href="style.css"> <title>Meme Generator using JavaScript - Coding Torque</title> </head> <body> <!-- Further code here --> <script src="script.js"></script> </body> </html>
Paste the below code in your <body>
tag.
<div class="header"> <h4>Meme Generator</h4> <div> <button id="export">CREATE</button> </div> </div> <div class="container"> <div> <div id="canvasWrapper"> </div> </div> <div class="memeForm"> <h5>Source Image</h5> <div class="box"> <div> <p>From URL</p> <div class="text_input"> <input id="imgURL" class="input" type="text" placeholder="Link to image" /> </div> </div> <div> <p>Upload from your device</p> <input id="imgFile" type="file" accept="image/*" /> </div> </div> <h4 style="margin-top: 50px;">Meme Text</h4> <div class="box"> <div> <p>Top Text</p> <div class="text_input"> <input id="textTop" type="text" class="input" placeholder="Top text" /> </div> </div> <div> <p>Bottom Text</p> <div class="text_input"> <input id="textBottom" type="text" class="input" placeholder="Bottom text" /> </div> </div> </div> <h4>Text Size</h4> <div class="box"> <div> <p>Top Text: <span id="textSizeTopOut">10</span></p> <div class="sliderContainer"> <input id="textSizeTop" type="range" min="2" max="50" step="2" /> </div> </div> <div> <p>Bottom Text: <span id="textSizeBottomOut">10</span></p> <div class="sliderContainer"> <input id="textSizeBottom" type="range" min="2" max="50" step="2" /> </div> </div> </div> <div class="box"> <div> <h4>Preview Size</h4> <input id="trueSize" type="checkbox" /> <label for="trueSize"><span>Show true size</span></label> </div> </div> </div> </div>
Output Till Now
CSS Code
Create a file style.css and paste the code below.
body { background: #1e293b; color: white; } .fullwidth { width: 100%; min-width: 400px; max-height: 800px; } .header { display: flex; align-items: center; justify-content: space-between; padding: 1rem 5rem; background-color: #334155; } #export { background: #3b82f6; color: white; border: none; border-radius: 4px; padding: 5px 20px; } .container { display: flex; padding: 0.5rem 5rem; } .memeForm { display: flex; flex-direction: column; justify-content: flex-start; padding-left: 2rem; } .box { display: flex; } .box div { margin-right: 30px; } .text_input { margin-bottom: auto; margin-top: auto; height: 50px; background-color: #353b48; border-radius: 30px; padding: 10px; } .input { color: white; border: 0; outline: 0; background: none; width: 250px; caret-color: transparent; line-height: 30px; transition: width 0.4s linear; padding: 0 10px; } .text_input:hover > .input { padding-right: 0 15px; caret-color: deepskyblue; transition: width 0.4s linear; } /* custom sliders for text sizes */ div.sliderContainer { width: 200px; text-align: center; } #textSizeTop, #textSizeBottom { -webkit-appearance: none; appearance: none; height: 18px !important; width: 100%; border-radius: 10em; background-color: deepskyblue; outline: none; margin-bottom: 14px; } #textSizeBottom::-webkit-slider-thumb, #textSizeTop::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 25px; height: 25px; border-radius: 50%; background: #3b82f6; cursor: pointer; border: 3px solid #f4f4f4; } #textSizeBottom::-moz-range-thumb, #textSizeTop::-moz-range-thumb { width: 25px; height: 25px; border-radius: 50%; background-color: #dbc500; cursor: pointer; border: 3px solid #f4f4f4; } input[type="checkbox"] { display: none; } input[type="checkbox"] + label { display: block; position: relative; padding-left: 35px; margin-bottom: 20px; font: 14px/20px "Open Sans", Arial, sans-serif; color: #ddd; cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; } input[type="checkbox"] + label:last-child { margin-bottom: 0; } input[type="checkbox"] + label:before { content: ""; display: block; width: 20px; height: 20px; border: 2px solid #6cc0e5; position: absolute; left: 0; top: 0; opacity: 0.6; -webkit-transition: all 0.12s, border-color 0.08s; transition: all 0.12s, border-color 0.08s; } input[type="checkbox"]:checked + label:before { width: 10px; top: -5px; left: 5px; border-radius: 0; opacity: 1; border-top-color: transparent; border-left-color: transparent; -webkit-transform: rotate(45deg); transform: rotate(45deg); }
JavaScript Code
Create a file script.js and paste the code below.
// CAN\NVAS.js plugin // ninivert, december 2016 (function (window, document) { /** * CAN\VAS Plugin - Adding line breaks to canvas * @arg {string} [str=Hello World] - text to be drawn * @arg {number} [x=0] - top left x coordinate of the text * @arg {number} [y=textSize] - top left y coordinate of the text * @arg {number} [w=canvasWidth] - maximum width of drawn text * @arg {number} [lh=1] - line height * @arg {number} [method=fill] - text drawing method, if 'none', text will not be rendered */ CanvasRenderingContext2D.prototype.drawBreakingText = function (str, x, y, w, lh, method) { // local variables and defaults var textSize = parseInt(this.font.replace(/\D/gi, '')); var textParts = []; var textPartsNo = 0; var words = []; var currLine = ''; var testLine = ''; str = str || ''; x = x || 0; y = y || 0; w = w || this.canvas.width; lh = lh || 1; method = method || 'fill'; // manual linebreaks textParts = str.split('\n'); textPartsNo = textParts.length; // split the words of the parts for (var i = 0; i < textParts.length; i++) { words[i] = textParts[i].split(' '); } // now that we have extracted the words // we reset the textParts textParts = []; // calculate recommended line breaks // split between the words for (var i = 0; i < textPartsNo; i++) { // clear the testline for the next manually broken line currLine = ''; for (var j = 0; j < words[i].length; j++) { testLine = currLine + words[i][j] + ' '; // check if the testLine is of good width if (this.measureText(testLine).width > w && j > 0) { textParts.push(currLine); currLine = words[i][j] + ' '; } else { currLine = testLine; } } // replace is to remove trailing whitespace textParts.push(currLine); } // render the text on the canvas for (var i = 0; i < textParts.length; i++) { if (method === 'fill') { this.fillText(textParts[i].replace(/((\s*\S+)*)\s*/, '$1'), x, y + (textSize * lh * i)); } else if (method === 'stroke') { this.strokeText(textParts[i].replace(/((\s*\S+)*)\s*/, '$1'), x, y + (textSize * lh * i)); } else if (method === 'none') { return { 'textParts': textParts, 'textHeight': textSize * lh * textParts.length }; } else { console.warn('drawBreakingText: ' + method + 'Text() does not exist'); return false; } } return { 'textParts': textParts, 'textHeight': textSize * lh * textParts.length }; }; })(window, document); var canvas = document.createElement('canvas'); var canvasWrapper = document.getElementById('canvasWrapper'); canvasWrapper.appendChild(canvas); canvas.width = 500; canvas.height = 500; var ctx = canvas.getContext('2d'); var padding = 15; var textTop = 'I use coding torque to learn'; var textBottom = 'web development by creating projects'; var textSizeTop = 10; var textSizeBottom = 10; var image = document.createElement('img'); image.onload = function (ev) { // delete and recreate canvas do untaint it canvas.outerHTML = ''; canvas = document.createElement('canvas'); canvasWrapper.appendChild(canvas); ctx = canvas.getContext('2d'); document.getElementById('trueSize').click(); document.getElementById('trueSize').click(); draw(); }; document.getElementById('imgURL').oninput = function (ev) { image.src = this.value; }; document.getElementById('imgFile').onchange = function (ev) { var reader = new FileReader(); reader.onload = function (ev) { image.src = reader.result; }; reader.readAsDataURL(this.files[0]); }; document.getElementById('textTop').oninput = function (ev) { textTop = this.value; draw(); }; document.getElementById('textBottom').oninput = function (ev) { textBottom = this.value; draw(); }; document.getElementById('textSizeTop').oninput = function (ev) { textSizeTop = parseInt(this.value); draw(); document.getElementById('textSizeTopOut').innerHTML = this.value; }; document.getElementById('textSizeBottom').oninput = function (ev) { textSizeBottom = parseInt(this.value); draw(); document.getElementById('textSizeBottomOut').innerHTML = this.value; }; document.getElementById('trueSize').onchange = function (ev) { if (document.getElementById('trueSize').checked) { canvas.classList.remove('fullwidth'); } else { canvas.classList.add('fullwidth'); } }; 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(); var win = window.open('', '_blank'); win.document.write('<img style="box-shadow: 0 0 1em 0 dimgrey;" src="' + img + '"/>'); win.document.write('<h1 style="font-family: Helvetica; font-weight: 300">Right Click > Save As<h1>'); win.document.body.style.padding = '1em'; }; function style(font, size, align, base) { ctx.font = size + 'px ' + font; ctx.textAlign = align; ctx.textBaseline = base; } function draw() { // uppercase the text var top = textTop.toUpperCase(); var bottom = textBottom.toUpperCase(); // set appropriate canvas size canvas.width = image.width; canvas.height = image.height; // draw the image ctx.drawImage(image, 0, 0, canvas.width, canvas.height); // styles ctx.fillStyle = '#fff'; ctx.strokeStyle = '#000'; ctx.lineWidth = canvas.width * 0.004; var _textSizeTop = textSizeTop / 100 * canvas.width; var _textSizeBottom = textSizeBottom / 100 * canvas.width; // draw top text style('Impact', _textSizeTop, 'center', 'bottom'); ctx.drawBreakingText(top, canvas.width / 2, _textSizeTop + padding, null, 1, 'fill'); ctx.drawBreakingText(top, canvas.width / 2, _textSizeTop + padding, null, 1, 'stroke'); // draw bottom text style('Impact', _textSizeBottom, 'center', 'top'); var height = ctx.drawBreakingText(bottom, 0, 0, null, 1, 'none').textHeight; console.log(ctx.drawBreakingText(bottom, 0, 0, null, 1, 'none')); ctx.drawBreakingText(bottom, canvas.width / 2, canvas.height - padding - height, null, 1, 'fill'); ctx.drawBreakingText(bottom, canvas.width / 2, canvas.height - padding - height, null, 1, 'stroke'); } image.src = 'https://imgflip.com/s/meme/The-Most-Interesting-Man-In-The-World.jpg'; document.getElementById('textSizeTop').value = textSizeTop; document.getElementById('textSizeBottom').value = textSizeBottom; document.getElementById('textSizeTopOut').innerHTML = textSizeTop; document.getElementById('textSizeBottomOut').innerHTML = textSizeBottom;
Final Output
Written by: Piyush Patil
If you found any mistakes or have any doubts please feel free to Contact Us
Hope you find this post helpful💖