Thursday, March 28, 2024

How to Make a Photo Collage Using HTML5 and CSS3

This article will show you a complete example of how to create a photo collage in HTML5 using CSS3 — from dragging and dropping images to saving the resulting photo collage image on your file. You will find all the needed files types are listed here, so can improve your photo collage skills.

In the figures below, you will see the structure of the files needed to create this application:

Getting Started

The index.html file contains the divs corresponding uploaded images that were created by dragging and dropping. You can also click in that area and an Open window will appear in which you can select your photo collage pattern. In our example, there are three patterns from which to choose, as you will see next. Another one will let you choose a background for your collage via browsing on your computer and the last option is to save your photo collage image, by pressing the link Save your collage image.

The index.html listing

<!DOCTYPE html>
<html>
    <head>
        <title>Collage photo's</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link href="css/styles.css" rel="stylesheet" type="text/css"/>
    </head>
    <body id="body">

        <h1>Collage</h1>

        <div class="row">
            <div class="column">

                <div id="leftSide">
                    <div id="dropZone">
                        <p>Drag your images from your file  sau click <u>here</u>!</p>
                    </div>

                    <div id="images_preview"></div>
                </div>

            </div>
            <div class="column">

                <div id="buttonsArea">
                    <select id="modelSelect" onchange="modelSelect()">
                        <option value="">Select the pattern</option>
                        <option value="model1">Model 1</option>
                        <option value="model2">Model 2</option>
                        <option value="model3">Model 3</option>
                    </select>

                    <div id="singleUploadSection">
                        Click "Browse" to select a background image for your canvas!
                        <input id="singleUpload" type="file" onchange="setBackground()"/>
                    </div>

                    <a href="#" class="button" id="btn-download">Save your collage image</a>
                </div>

            </div>

            <div id="photo">

                <canvas id="background" width="600" height="600"></canvas>

            </div>

            <div id="images"></div>
        </div>

        <script src="js/jquery-3.2.1.min.js"></script>
        <script src="js/fileUpload.js"></script>
        <script src="js/script.js"></script>
    </body>
</html>

The styles.css file

styles.css

/**************
* Page Layout *
**************/
body {
    margin: 0;
    background-color: #e1e6c4;
}

* {
    box-sizing: border-box;
}

/* Create columns that floats next to each other */
.column {
    float: left;
}

/* Clear floats after the columns */
.row:after {
    content: "";
    display: table;
    clear: both;
}

/******************
* Style for title *
******************/
h1 {
    color: #239aca;
    text-align: center;
}

h1:first-letter{
    color:#1B6685;
}

/******************************
* Style for left side content *
******************************/
#leftSide {
    color: #aaa;
    width: 186px;
    padding: 5px;
    margin: 0 20px;
    overflow: auto;
    background-color: #fff;
    border: dashed 1px #bbb;
    box-shadow: 0px 0px 0px 5px #f7f7f7, 0px 0px 2px 7px #bbb, 0px 0px 5px 5px #f7f7f7 inset;
}

/***************************
* Style for drop zone area *
***************************/
#dropZone {
    padding: 30px 0;
    margin-bottom: 8px;
    text-align: center;
}

#dropZone.dragover {
    background: #DCDCDC;
}

/**************************
* Style for image preview *
**************************/
img {
    margin: 0 3px;
}
img:hover {
    cursor: grab;
}

/*********************************************
* Style for model selection drop-down button *
*********************************************/
#buttonsArea {
    margin: 0 15px 0 50px;
}

select {
    color: #333;
    display: block;
    max-width: 100%;
    border-radius: 3px;
    height: auto !important;
    border: 1px solid #e3e3e3;
    line-height: 16px !important;
    padding: 10px 70px 10px 13px !important;
    background: #fff url("selectbox_arrow.png") right center no-repeat;
    appearance: none; /* this is must */
    -webkit-appearance: none;
    -moz-appearance: none;
}

/*****************************************************************
* Style for single upload section that changes canvas background *
*****************************************************************/
#singleUploadSection {
    color: #333;
    width: 194px;
    padding: 6px;
    margin: 10px 0;
    font-size: 13px;
    text-align: center;
    border-radius: 3px;
    background-color: #fff;
}

/*******************
* Style for canvas *
*******************/
#background {
	padding: 5px;
    position: absolute;
    background-color: #fff;
	box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}

.layer {
	padding: 5px;
    position: absolute;
    background-color: #fff;
}

The fileUpload.js listing

/*
 * This file is used for drag & drop file upload and image preview
 */

/************************************************************
 * Add the JavaScript support for drag & drop/browse upload *
 ***********************************************************/
function makeDroppable(element, callback) {
    var input = document.createElement('input');
    input.setAttribute('type', 'file');
    input.setAttribute('multiple', true);
    input.style.display = 'none';
    input.addEventListener('change', function (e) {
        triggerCallback(e, callback);
    });
    element.appendChild(input);

    element.addEventListener('dragover', function (e) {
        e.preventDefault();
        e.stopPropagation();
        element.classList.add('dragover');
    });

    element.addEventListener('dragleave', function (e) {
        e.preventDefault();
        e.stopPropagation();
        element.classList.remove('dragover');
    });

    element.addEventListener('drop', function (e) {
        e.preventDefault();
        e.stopPropagation();
        element.classList.remove('dragover');
        triggerCallback(e, callback);
    });

    element.addEventListener('click', function () {
        input.value = null;
        input.click();
    });
}

function triggerCallback(e, callback) {
    if (!callback || typeof callback !== 'function') {
        return;
    }
    var files;
    if (e.dataTransfer) {
        files = e.dataTransfer.files;
    } else if (e.target) {
        files = e.target.files;
    }
    callback.call(null, files);
}

/*************************************************************************
 * After drag & drop upload, create image elements and add image preview *
 * Make images draggable to canvas and register mouse & drag events      *
 ************************************************************************/
makeDroppable(document.querySelector('#dropZone'), function (files) {
    var output = document.querySelector('#images_preview');
    output.innerHTML = '';

    for (var i = 0; i < files.length; i++) {
        if (files[i].type.indexOf('image/') === 0) {

            var reader = new FileReader();
            reader.addEventListener("load", function () {
                var image = new Image();
                image.id = Math.random().toString(36).substr(2, 9);    // Generate image ID
                image.height = 80;
                image.width = 80;
                image.src = this.result;

		    image.ondragstart = function (e) {  // Register drag event						  
		    e.dataTransfer.setData("text", e.target.id);
                };
				
                output.appendChild(image);      // Add image preview to page

            }, false);
            reader.readAsDataURL(files[i]);
        }
    }
});

The script.js file

/*
 * This file is used for interaction with the canvas element and initializations
 */

/*******************************************************
 * Change canvas 1 background after image was selected *
 ******************************************************/
function setBackground() {
    var file = $("#singleUpload")[0].files[0];
    var canvas = document.getElementById("background");
    var context = canvas.getContext("2d");
    var reader = new FileReader();
    reader.addEventListener("load", function () {
        var backgroundImage = new Image();
        backgroundImage.src = this.result;
        backgroundImage.onload = function () {
            context.drawImage(backgroundImage, 0, 0, 600, 600);      // Draw and stretch 
            image to fill canvas
        };
    }, false);
    reader.readAsDataURL(file);
}

/*************************************
 * Global variables, initialisations *
 ************************************/
$("#singleUpload").val("");                // Reset background selection on page refresh
$("#modelSelect").val("");                 // Reset model selection on page refresh

document.getElementById("background").style.visibility = "hidden";              // Hide canvas until model is selected

/**************************************
 * Export canvas and download as imag *
 *************************************/
var link = document.getElementById('btn-download');
link.addEventListener('click', function (e) {

    var canvas = document.createElement('canvas');
    var context = canvas.getContext("2d");
    canvas.width = 605;
    canvas.height = 605;

    // We need to get all images droped on all canvases and combine them on above canvas
    $('#photo').children('canvas').each(function () {
        var image = this;
        
        context.beginPath();      // Simulate CSS padding around images by drawing white 
 	  rectangles behind images on export
        context.rect((image.offsetLeft - 480), (image.offsetTop - 76), image.width, 
        image.height);
        context.fillStyle = "white";
        context.fill();
        
        context.drawImage(image, (image.offsetLeft - 480 + 5), (image.offsetTop - 76 + 5), 
        (image.width - 10), (image.height - 10));    // Draw image
    });

    link.href = canvas.toDataURL();   // Save all combined images to one image
    link.download = "photo.png";      // Download the image
}, false);

/***************************************
 * Change model after drop-down select *
 **************************************/
function modelSelect() {

    var background = document.getElementById("background"); // Keep background canvas

    var photo = document.getElementById("photo");
    while (photo.firstChild) {                              // Remove all child canvases
        photo.removeChild(photo.firstChild);
    }
    photo.appendChild(background);                          // Attach background canvas back

    var selectedModel = document.getElementById("modelSelect").value;    // Get the selected 
    model value

    switch (selectedModel) {

        case "model1":             // If model1 was selected, draw pattern using 3 new 
            canvas elements as layers on top of background canvas

            document.getElementById("background").style.visibility = "visible"; // Make 
            background canvas visible

            var layer1 = document.createElement('canvas'); // Create first square canvas 
            programmatically
            layer1.className = "layer";
            layer1.width = 200;                   // Set square canvas width
            layer1.height = 200;                  // Set square canvas height
            layer1.style.top = "130px";           // Position square canvas 130px from top
            layer1.style.left = "540px";          // Position square canvas 540px from left
            layer1.style.visibility = "visible";

            var body = document.getElementById("photo");
            body.appendChild(layer1); // Add first square canvas to photo element on page
            registerEvents(layer1); // Add event listeners that help drag & drop on canvas

            var layer2 = document.createElement('canvas');      // Same as above ... create 
            second square canvas.. etc
            layer2.className = "layer";
            layer2.width = 110;
            layer2.height = 110;
            layer2.style.top = "180px";
            layer2.style.left = "840px";
            layer2.style.visibility = "visible";

            var body = document.getElementById("photo");
            body.appendChild(layer2);
            registerEvents(layer2);

            var layer3 = document.createElement('canvas');
            layer3.className = "layer";
            layer3.width = 340;
            layer3.height = 230;
            layer3.style.top = "400px";
            layer3.style.left = "670px";
            layer3.style.visibility = "visible";

            var body = document.getElementById("photo");
            body.appendChild(layer3);
            registerEvents(layer3);

            break;

        case "model2":  // If model2 was selected, draw pattern using 2 new canvas elements 
        as layers on top of background canvas

            document.getElementById("background").style.visibility = "visible";

            var layer1 = document.createElement('canvas');
            layer1.className = "layer";
            layer1.width = 250;
            layer1.height = 250;
            layer1.style.top = "81px";
            layer1.style.left = "485px";
            layer1.style.visibility = "visible";

            var body = document.getElementById("photo");
            body.appendChild(layer1);
            registerEvents(layer1);

            var layer2 = document.createElement('canvas');
            layer2.className = "layer";
            layer2.width = 150;
            layer2.height = 600;
            layer2.style.top = "81px";
            layer2.style.left = "785px";
            layer2.style.visibility = "visible";

            var body = document.getElementById("photo");
            body.appendChild(layer2);
            registerEvents(layer2);

            break;

        case "model3":  // If model3 was selected, draw pattern using 2 new canvas elements 
        as layers on top of background canvas

            document.getElementById("background").style.visibility = "visible";

            var layer1 = document.createElement('canvas');
            layer1.className = "layer";
            layer1.width = 250;
            layer1.height = 250;
            layer1.style.top = "81px";
            layer1.style.left = "485px";
            layer1.style.visibility = "visible";

            var body = document.getElementById("photo");
            body.appendChild(layer1);
            registerEvents(layer1);

            var layer2 = document.createElement('canvas');
            layer2.className = "layer";
            layer2.width = 300;
            layer2.height = 600;
            layer2.style.top = "81px";
            layer2.style.left = "785px";
            layer2.style.visibility = "visible";

            var body = document.getElementById("photo");
            body.appendChild(layer2);
            registerEvents(layer2);

            break;

        default:
            document.getElementById("background").style.visibility = "hidden";  // Hide 
            canvas until model is selected
    }
}

/**********************************************************
 * Register drag & drop event listeners to canvas element *
 *********************************************************/
function registerEvents(canvas) {

    canvas.ondragenter = function () {
        canvas.style.border = "dashed 2px #555";  // Change the canvas borders when hovering
    };
    canvas.ondragleave = function () {
        canvas.style.border = "none";    // Reset canvas borders when hovering is not active
    };
    canvas.ondragover = function (e) {
        e.preventDefault();
    };
    canvas.ondrop = function (e) {
        e.preventDefault();
        var id = e.dataTransfer.getData("text");
        var dropImage = document.getElementById(id);
        canvas.style.border = "none";              // Reset canvas borders after image drop

        var context = canvas.getContext("2d");
        context.drawImage(dropImage, 0, 0, canvas.width, canvas.height);     // Draw and stretch image to fill canvas
    };
}

Next, are some screenshots of different photo collage options that are available using the three patterns:

Conclusion

This article has shown you how to create a photo collage with your own images using HTML5 and CSS3.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles

Featured