Drag & Drop upload obrázků
Všechny možnosti nahrávání obrázků ze schránky a pomocí drag & drop.
Pro maximální pohodlí návštěvníka při nahrávání obrázků na web existuje řada postupů, které fungují v různých prohlížečích.
Ukázka maximálních možností uploadu běží na: img.djpw.cz
Vložení ze schránky
Příjemná funkce je vložení obrázku ze schránky. Zde se situace lehce komplikuje, neboť mohou nastat dva případy vložení.
-
Uživatel zkopíruje celý soubor. Buď přes kontextové menu, nebo například klávesovou zkratkou Ctrl + C.
- Uživatel zkopíruje kus (výřez) obrázku do schránky. To může nastat v grafickém editoru, také po vyfocení obrazovky klávesou PrintScreen (či jen aktivního okna – Alt + PrintScreen) nebo třeba v prohlížeči po vybrání volby Kopírovat obrázek z kontextového menu.
Využití contenteditable
Ve Firefoxu a IE 11 je možné využít toho, že tyto prohlížeče umí (například) screenshot obrazovky vložit jako obrázek do elementu s contenteditable
/designMode
(tak si je možné vytvořit i vlastní WYSIWYG edtior).
Firefox takto umí dokonce i vkládat zkopírované soubory.
Živá ukázka – vložení obrázku ze schránky do contenteditable
Jinde to ale nefunguje. Ve staré Opeře 12 a starších IE není možnost obrázek ze schránky vložit (jen s využitím HTML a JS) v jakékoliv podobě bez použití nějakých pluginů v Javě nebo Flashi.
V Chrome jde použít clipboardData
.
Živá ukázka – získání souboru z clipboardData
Drag & Drop souborů
Kromě vložení přes Ctrl + V se může hodit i nahrání souboru jeho přetažením na stránku.
V Chrome, nové Opeře a Firefoxu jde soubor přesunout přímo na <input type="file">
bez nutnosti dalšího programování. Internet Explorer ani MS Edge toto neumí.
Jelikož je ale dobré mít uploadování funkční i v IE a navíc se hodí mít pro přesun souborů vyhrazenou větší plochu, která bude po přetažení navíc signalisovat možnost tažený soubor upustit, je řešení pomocí <input type="file">
celkem nedostatečné.
Nejdříve je nutné zablokovat výchozí akci prohlížeče při přetáhnutí souboru, což někde způsobí nežádoucí přechod na obrázek. Slouží k tomu drag & drop událostí:
function prevent(e) {
e = e || event;
e.preventDefault();
}
window.addEventListener("dragover", prevent, false);
window.addEventListener("drop", prevent, false);
Přetažený soubor (nebo soubory) se získají z event.dataTransfer.files
při události ondrop
(upuštění obrázku).
Živá ukázka – výpis přetažených souborů
Zvýraznění při přesouvání
Aby uživatel poznal, že stránka na přesouvání souboru reaguje, použijí se příslušné drag & drop události myši.
ondragenter
– uživatel najel se souborem na oblast (provést zvýraznění)ondragleave
– uživatel najel se souborem na oblast (zrušit zvýraznění)ondrop
– uživatel soubor v dané oblasti pustil
Zobrazení souboru
Když člověk vybere soubor (je jedno, jestli přesunutím na <input type="file">
nebo po kliknutí na tlačítko Vybrat) či použije přetažení myší, je dobré obsah obrázku ihned zobrazit.
Kromě toho, že návštěvník získá jistotu, že vybral správný obrázek a uvidí ho prakticky ihned, lze nabídnout i nějaké základní funkce pro práci s obrázky:
- změnu velikosti,
- oříznutí,
- otočení/převrácení
To lze v dnešních prohlížečích řešit na straně klienta bez nutnosti přenášet data na server. Zvlášť výhodné je to u zmenšování obrázků, což je výborné i pro uživatele, neboť nemusí třeba X megabytový soubor vůbec nikam přenášet, ale nahraje se jen jeho zmenšenina.
Slouží k tomu FileReader:
FileReader
Řešení pomocí FileReader
funguje od IE 10. Pro vložení souboru jako obrázku na stránku je potřeba z původního souboru udělat data URL, která se nastaví jako src
pro <img>
(popř. se následně tento obrázek může nakreslit do <canvas>
u). Převod na data URL řeší metoda readAsDataURL
, které se jako argument předá soubor získaný z políčka pro nahrávání souborů nebo pomocí dataTransfer
při přesunutí souboru do stránky pomocí drag&dropu.
FileReader se používá velmi jednoduše:
var reader = new FileReader();
reader.onload = function (e) {
obrazek.src = e.target.result;
};
reader.readAsDataURL(soubor);
- Proměnná
obrazek
je<img>
značka na stránce, kde se obrázek objeví. - Proměnná
soubor
obsahuje soubor získaný přesdataTransfer.files
/input.files
.
Za povšimnutí stojí konstrukce reader.onload
, která se spustí po dokončení readAsDataURL
.
Zobrazení přetaženého souboru
Hotové řešení zobrazení obrázku po drag & drop může vypadat následovně:
Živá ukázka – zobrazení obrázku před uploadem
Zobrazení souboru z <input>
u
V případě políčka <input>
se celý proces náhledu nabízí volat při změně (onchange
) nahrávacího <input>
u.
<input type="file" onchange="zobrazit(this)">
Funkci zobrazit
se předává nahrávací políčko (this
) právě kvůli následnému získání souboru z input.files
.
Živá ukázka – okamžitého zobrazení obrázku z <input type="file">
Více souborů najednou
Pro upload více souborů existuje HTML atribut multiple
. V takovém případě bude záhodno zobrazit náhledy všech souborů. Počet souborů se zjistí z input.files.length
. Potom stačí soubory projít běžným cyklem for
a místo nuly na místě indexu použít index každého jednoho souboru.
Živá ukázka – zobrazení více souboru z multiple
upload políčka.
Zobrazení více (datově větších) souborů zabere nějaký čas. Tudíž by bylo dobré dát uživateli vědět, že se něco děje.
Kreslení do <canvas>
u
Překreslit obrázek do elementu <canvas>
jde metodou drawImage
. Nejdříve se v HTML kódu připraví plátno (<canvas>
).
<canvas id="cc"></canvas>
Do pomocných proměnných se přidá odkaz na <canvas>
a jeho 2D kontext.
var canvas = document.getElementById("cc");
var ctx = canvas.getContext("2d");
A do funkce prováděné při reader.onload
se pár řádky nakreslí na plátno obrázek. Může se hodit i nastavit <canvas>
u rozměry podle obrázku.
canvas.width = obrazek.width;
canvas.height = obrazek.height;
ctx.drawImage(obrazek, 0, 0);
Druhý a třetí parametr funkce drawImage
určuje souřadnice, kam se má obrázek nakreslit – cílem je ho umístit hned do levého horního rohu, proto ty dvě nuly. Proměnná obrazek
je <img>
element.
Živá ukázka – překreslení obrázku do <canvas>
u
Kvůli IE musí obrázek na stránce skutečně existovat (být přidán do DOMu), byť třeba skrytý.
var obrazek = new Image();
obrazek.src = e.target.result;
Tato elegantnější konstrukce proto nebude v IE fungovat (ukázka).
Zobrazení textu před uploadem
Také textový soubor je možné před samotným nahráváním zobrazit.
Místo metody readAsDataURL
k tomu slouží přečtení souboru jako text – readAsText
a výsledek se nastaví jako innerHTML
nějakého elementu.
Starší prohlížeče
V IE 9 a starších není možné použít FileReader
. Pro zobrazení náhledu tak nezbývá než soubor nahrát na server a až ten zobrazit. Případně použít nějaký plugin ve Flashi nebo Javě.
Údajně by ve starších IE mohlo fungovat tohle – ukázka – v IE 9 to ale funkčně nevypadá.
Upload souboru
Samotný proces nahrání souboru na server proběhne například odesláním AJAXového požadavku. Jako data se odešle data URL.
Obsah <canvas>
u se získá prostým canvas.toDataURL()
.
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
alert(xhr.responseText); // výstup PHP skriptu
}
}
xhr.open("POST", "upload.php");
xhr.setRequestHeader(
"Content-type",
"application/x-www-form-urlencoded"
);
xhr.send("data=" + canvas.toDataURL());
PHP skript upload.php
, který tento obsah uložit do souboru může vypadat takto:
if (isset($_POST["data"])) {
$img = $_POST["data"];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$filename = time() . ".png";
file_put_contents($filename, $data);
echo $filename;
}
else {
echo "Error";
}
-
Při ukládání souborů je v praxi dobré zajistit, aby nemohlo vzniknout hodně souborů v rámci jedné složky.
Taktéž určování názvu souboru podle timestampu (času požadavku na uložení) nebude v případě používání uploadu více uživateli ideální. Mohli by si navzájem obrázky přepisovat.
Lepší postup je o obrázcích ukládat záznam v databási a fysický obrázek na serveru pojmenovat až na základě identifikátoru v DB (popř. nějakým hashem).
-
Skript natvrdo ukládá obrázky jako PNG. To v případě například fotek nebude s ohledem na datovou velikost optimální formát.
Odkazy jinam
- img.djpw.cz – můj nahrávač souborů obsahující všechny popsané postupy
- MDN: DataTransfer
- Odchycení vložení obrázku ze schránky (ukázka)
- PHP triky: Ukládání souborů od uživatele
- Medio Blog: Jak ukládáme obrázky
- The New Code: Upload and Upgrade: The HTML File Form Input
Komentáře