Passa al contingut principal

HTML5 Drag and Drop Avatar Changer with Resizing and Cropping

In any app that has user avatars, users should be able to change those avatars. Anything to make that easier is desirable. Many apps start with a user's Twitter avatar, Facebook avatar, or Gravatar. That's a smart move. Avatars give users a sense of ownership over a virtual space so any way to get them to have their desired avatar is good for engagement.


Let's create a page where a user can update their avatar with as little friction as possible: they just drop an image anywhere on the page and it's done.



View Demo


The Workhorse of Drag and Drop


Perhaps the most important bit we'll deal with is the drop event. This is where we get access to the file and can do what we need to do with it. We'll be using jQuery to help us with events and whatnot.



// Required for drag and drop file access
jQuery.event.props.push('dataTransfer');

$("body").on('drop', function(event) {

// Or else the browser will open the file
event.preventDefault();

// Do something with the file(s)
var files = event.dataTransfer.files;

}


Interestingly enough, as written, the above won't work. One more bit is required, and that is to prevent the default of the dragover event as well. That's fine, as we will be using that event to make some kind of UI change to emphasize "dropability."



$("body").on("dragover", function(event) {

// Do something to UI to make page look droppable

// Required for drop to work
return false;
});


And of course remove that UI change if the user doesn't perform the drop:



$("body").on("dragleave", function(event) {

// Remove UI change

});


Handling the Dropped File


Drag and drop can do multiple files. We're only dealing with one file here, so let's just use the first one.



$("body").on('drop', function(event) {
event.preventDefault();

var file = event.dataTransfer.files[0];

if (file.type.match('image.*')) {
// Deal with file
} else {
// However you want to handle error that dropped file wasn't an image
}

}


Perhaps if you were really nice, you'd loop over all the files and find the first image rather than rejecting based on the first file.


Resizing the Avatar


There are server side ways to resize images, but that requires a round trip (slow) and the transfer of potentially enormous files (slow). We can resize the avatar to the size we want for our app right on the client side. This is wicked fast.


You can do this by creating a <canvas>, drawing the image to the canvas, then exporting the canvas as a Data URI. Andrea Giammarchi has an excellent script for this. You would just include this script before all this custom code we're writing.


Squaring Avatars


In our example, all our avatars are squares. Squaring is a little tricky. Do you allow rectangles and just center them? Do you apply whitespace around edges so rectangles are really squares? Do you crop the image so it's a square? If you do crop, from what original point do you do the cropping? Do you crop before or after the resizing?



  1. Let's go with cropping.

  2. Let's not bother the user about it at all. There are ways to build UI cropping tool for users to pick their own crop, but let's not make an extra step for them and just do it automatically

  3. Let's crop from the top/left.


All this canvas stuff was a bit over my head. Fortunately Ralph Holzmann was able to jump in an help me alter Andrea's original script to handle cropping.


Crop / Resize In Action


With those parts ready to go, we can crop and resize by calling our new script that does both:



var fileTracker = new FileReader;
fileTracker.onload = function() {
Resample(
this.result,
256,
256,
placeNewAvatar
);
}
fileTracker.readAsDataURL(file);


placeNewAvatar is a custom callback function that we'll provide that receives the newly resized data URI we can place on the page.



function placeNewAvatar(data) {
$("#profile-avatar").attr("src", data);
}


Uploading and Saving Avatar


You'll probably want to save your resized avatar, not the original. You know, keep things fast and storage low.


It would be silly to trigger a page load to upload the file, since we're already using fancy drag and drop. So we're looking at Ajaxing the file to the server. Perhaps you're server is totally fine accepting and saving that Data URI. In that case, just send 'er up however. Maybe like



$.post({
url: "/your/app/save/image/whatever",
data: data
});


But if you're using some kind of asset host, they will probably want a real file, not a data URI. And they'll want you to POST them multipart/form-data not just a string. So you'll need to change that data URI into a file (or "Blob").



function dataURItoBlob(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}


You also can't use jQuery to Ajax the file anymore, because it's Ajax methods won't let you pass FormData() in my experience. So you'll have to do it manually, which is fine since drag and drop more new-fangled than Ajax anyway.



var xhr = new XMLHttpRequest();
var fd = new FormData();

fd.append('file', resampledFile);

xhr.open('POST', "/your/app/save/image/whatever", true);
xhr.send(fd);


Relevant CSS Bits


If you're going to watch for the drop event on the body, you should make sure the body is at least as tall as the page. Otherwise there might be some space toward the bottom that won't take the event.



html, body {
height: 100%;
}


Also, the drag event isn't only fired by files that you drag in from outside the browser window, it can be fired by dragging an image already placed on the page. To prevent this, I wrap the image in a div and apply a pseudo element over the entire div. This prevents the dragging of that image.



.profile-avatar-wrap {
position: relative;
}
.profile-avatar-wrap:after {
/* Drag Prevention */
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}


This works with the file input as well


As a fallback, you could include a file input as well. How exactly you want to handle that is up to you. For example, inject it on a feature detection fail, or just supply both on the page.



<input type="file" id="uploader">

Everything would be pretty much the same, only access to the file would happen on:



$("#uploader").on('change', function(event) {
var file = event.target.files[0];
});


This is particularly relevant for mobile where drag and drop is rather irrelevant.


Not Quite Done


Here's the demo:


View Demo


I'm not even quite sure the browser support. Here's CanIUse for drag and drop and canvas.


I'm sure I haven't handled everything quite perfectly here. For one thing, it doesn't seem to work in Opera. The drag and drop stuff seems to work (it asks you if you want to upload the file) but never quite processes.


It does work in Chrome/Safari/Firefox.


For another thing, I handled the "Drop File Anywhere" thing by adding a pseudo element to the body. Sometimes it gets a little "flashy". It's an improvement for when I tried doing it with a div, but not great. I also tried only doing and UI action when the dragleave event originated on the body itself.



$("body").on("dragleave", function(event) {
if (event.currentTarget == $("body")[0]) {
$("body").removeClassClass("droppable");
}

// Required for drop to work
return false;
});


But no dice.


And finally, the code shown in this article isn't organized. In real life, you would organize all this. Here is the organized code. If you can fix stuff or make it better, I tossed it on GitHub so feel free to submit a pull request (how).


HTML5 Drag and Drop Avatar Changer with Resizing and Cropping is a post from CSS-Tricks






via CSS-Tricks http://css-tricks.com/html5-drag-and-drop-avatar-changer-with-resizing-and-cropping/

Comentaris

Entrades populars d'aquest blog

Learn Composition from the Photography of Henri Cartier-Bresson

“Do you see it?” This question is a photographic mantra. Myron Barnstone , my mentor, repeats this question every day with the hopes that we do “see it.” This obvious question reminds me that even though I have seen Cartier-Bresson’s prints and read his books, there are major parts of his work which remain hidden from public view. Beneath the surface of perfectly timed snap shots is a design sensibility that is rarely challenged by contemporary photographers. Henri Cartier-Bresson. © Martine Franck Words To Know 1:1.5 Ratio: The 35mm negative measures 36mm x 24mm. Mathematically it can be reduced to a 3:2 ratio. Reduced even further it will be referred to as the 1:1.5 Ratio or the 1.5 Rectangle. Eyes: The frame of an image is created by two vertical lines and two horizontal lines. The intersection of these lines is called an eye. The four corners of a negative can be called the “eyes.” This is extremely important because the diagonals connecting these lines will form the breakdown ...

El meu editor de codi preferit el 2024, que això ja se sap que va canviant 😄

Visual Code Visual Code és un editor de codi font lleuger, però potent que s’executa al teu escriptori i està disponible per a Windows, macOS i Linux. Compta amb suport integrat per a JavaScript, TypeScript i Node.js i té un ric ecosistema d’extensions per a altres llenguatges i entorns d’execució (com C++, C#, Java, Python, PHP, Go, .NET).  És una eina ideal per a desenvolupar i depurar aplicacions web i en el núvol. Per què Visual Code? Visual Code té molts avantatges com a editor de codi font, com per exemple: És gratuït, ràpid i fàcil d’instal·lar i actualitzar. Té un ampli ecosistema d’extensions que et permeten afegir funcionalitats i personalitzar la teva experiència de desenvolupament. Té un suport integrat per a molts llenguatges i entorns d’execució, i et permet depurar i executar el teu codi des del mateix editor. Té una interfície senzilla i elegant, amb diferents temes i modes de visualització. Té un sistema de sincronització de configuracions que et permet guardar les...

Las Mejores Aplicaciones Gratis para iPad de 2012

Las Mejores Aplicaciones Gratis para iPad de 2012 : ¿No tienes ni un duro? No te preocupes, pues hoy os traemos una extensa selección de las mejores apps gratuitas que puedes conseguir en la App Store para que llenes tu iPad de calidad, sin gastar nada de nada.   ¿Estás buscando juegos o apps gratis para tu iPad? En la App Store hay más de 500,000 apps y juegos, y una gran cantidad de ellos está disponible de forma totalmente gratuita. Aquí vamos con la selección de las mejores Apps gratis para iPad (todos los modelos), organizada por categoría. ¿Estás preparado? Las Mejores Apps Gratis de Redes Sociales para iPad Nombre Facebook Gratis Categoría Redes sociales Facebook es la red social más famosa del mundo , con casi mil millones de usuarios. Su app para iPad ha tardado, pero aquí está. Nombre Twitter Gratis Categoría Redes sociales Twitter es la red de microblogging por excelencia. La forma más rápida y directa de informar y mantenerse informado de las cosa...