Dank dem Canvas-Element sind komplexe Zeichnungen und Zeichenfunktionen in HTML-Seiten möglich. Für Formulare ergeben sich somit neue Möglichkeiten, wie die Umsetzung einer Unterschriftenfunktion.
In unserem Beispiel wollen wir ein Formular erstellen, welches dem Benutzer erlaubt eine Unterschrift (oder jede beliebige andere Zeichnung) zu erstellen. Wahlweise mit Maus oder auf mobilen Geräten mit Touch-Funktionen.
Das Formular wird anschließend von einem PHP-Script verarbeitet. Unser Beispiel wird so aussehen:
Wie man bereits am Screenshot sehen kann, wollen wir das Rad nicht komplett neu erfinden, sondern verwenden eine Open-Source-Komponente für die Basisfunktionen. Die Komponente verwendet unterschiedliche Strichstärken beim Zeichnen, so dass der Eindruck eines echten Stiftes bzw. Unterschrift entsteht.
Legen wir los. Das gesamte Beispiel gibt es am Ende als Download. Im ersten Schritt legen wir uns eine HTML-Datei an. Dort fügen wir kurz dem schließenden Body-Tag die Java-Script Bibliothek für die Unterschrift ein:
<script src="signature_pad.js"></script>
Anschließend definieren wir in unserem Formular die Elemente für unter Unterschriftenfeld:
<div id="signature-pad" class="m-signature-pad"> <div class="m-signature-pad--body"> <canvas></canvas> <input type="hidden" name="signature" id="signature" value=""> </div> </div>
Wir sehen hier ein leeres Canvas, welches später mal unser Unterschriftfeld realisieren wird. Auch ein verstecktes Formularfeld, dieses verwenden wir zum übermitteln der Daten an unser PHP-Script.
Für die Festlegung unseres Designs verwenden wir etwas CSS-Code:
<style type="text/css"> .m-signature-pad--body canvas { position: relative; left: 0; top: 0; width: 100%; height: 250px; border: 1px solid #CCCCCC; } </style>
Hier können wir Breite, Höhe und Rahmenfarbe festlegen. Nun müssen wir das Canvas noch mit den entsprechenden Funktionen verdrahten:
var wrapper = document.getElementById("signature-pad"), canvas = wrapper.querySelector("canvas"), signaturePad; var signaturePad = new SignaturePad(canvas); signaturePad.minWidth = 1; //minimale Breite des Stiftes signaturePad.maxWidth = 5; //maximale Breite des Stiftes signaturePad.penColor = "#000000"; //Stiftfarbe signaturePad.backgroundColor = "#FFFFFF"; //Hintergrundfarbe
Dies verbindet unser Canvas mit dem Java-Script der Komponente und erlaubt nun ein Zeichnen in den Canvas. Außerdem können wir gleich verschiedene Eigenschaften, wie Farben, Stiftstärken und Hintergrundfarbe festlegen.
Nun funktioniert das Zeichnen schon mal, reagiert aber nicht optimal auf Größenänderungen des Browsers. Daher müssen wir die Behandlung von Größenänderungen des Browsers noch implementieren:
function resizeCanvas() { var oldContent = signaturePad.toData(); var ratio = Math.max(window.devicePixelRatio || 1, 1); canvas.width = canvas.offsetWidth * ratio; canvas.height = canvas.offsetHeight * ratio; canvas.getContext("2d").scale(ratio, ratio); signaturePad.clear(); signaturePad.fromData(oldContent); }
Diese Funktion weisen wir dem Event des Browserfensters zu und rufen die Methode auch gleich beim ersten Aufruf einmal auf:
window.onresize = resizeCanvas; resizeCanvas();
Wozu das Ganze? Bei Größenänderungen des Browsers verändert sich der Inhalt des Canvas, wird u.U. sogar gelöscht, gestaucht etc. Daher speichern wir den Originalinhalt, ermitteln die neue Größe und setzen den alten Inhalt in das vergrößerte oder verkleinerte Canvas.
Was nun noch fehlt ist die Übermittlung der Unterschrift an ein verarbeitendes PHP-Script. Das Canvas-Element wird nicht übertragen, wenn man das Formular abschickt. Daher speichern wir den Inhalt im Data-URL-Format in das versteckte Feld:
function submitForm() { //Unterschrift in verstecktes Feld übernehmen document.getElementById('signature').value = signaturePad.toDataURL(); }
Die Komponente hat praktischerweise eine Funktion, mit welcher wir den Bildinhalt direkt als Data-URL zurückbekommen. Diese Funktion müssen wir nun noch vor dem Versand des Formulars aufrufen, dies können über das Entsprechende Event des Formulars erledigen:
<form class="w3-container" action="process.php" method="POST" name="DAFORM" onSubmit="submitForm();" enctype="multipart/form-data" target="_self">
Fertig. Beim Absenden wir die Unterschrift, bzw. das Bild im ASCII-Format in das versteckte Feld gespeichert. Dort finden wir im PHP-Script dann z.B. folgenden Inhalt vor:
data:image/png;base64,iVBORw0KGgoAAAAN…
Der Vorteil des Data-URL-Formats? Nun wir können den Inhalt direkt verwenden um das Bild in einem Image-Tag darzustellen:
<img src="data:image/png;base64,iVBORw0KGgoAAAAN...">
Dies machen wir uns nun auch im PHP-Script zu nutze. Hier lesen wir einfach die POST-Variable des Formulars aus und geben das Bild aus:
$image = ""; if (isset($_POST["signature"])) { $image = $_POST["signature"]; echo ""; } else { echo "
Kein Bild übertragen
"; }
Das Ergebnis:
Und schon haben wir ein Formular mit Unterschriften- bzw. Zeichenfunktion erstellt. Im Beispiel finden Sie noch die Möglichkeit das Feld mit einem Button zu löschen, sowie das Bild direkt im Browser als Bild herunter zu laden.
Download des Beispiels
Das komplette Beispiel gibt es hier. Download der Orignalkomponente auf Github.
Integration im DA-FormMaker
Noch ein Tipp, wem das Ganze zu viel Handarbeit ist: Die gesamte Funktionalität von Zeichnung- bzw. Unterschriftenfeld befindet sich bereits fertig integriert in unserer Software DA-FormMaker und DA-BestellFormular. Den Formularen können beliebig viele Unterschriftenfelder hinzugefügt werden. Die Konfiguration von Farben, Design, Größe werden direkt in der Software vorgenommen. Auch Überprüfungen auf leere Felder sind möglich:
Der Code wird automatisch generiert und Formular mit Unterschriftenfeld sind sofort einsetzbar. Wird das Formular abgeschickt, wird die Unterschrift inline in der HTML-E-Mail angezeigt. Zusätzlich wird die Zeichnung als PNG-Datei im Anhang eingefügt.
Hallo Andy,
vielen Dank für die ausführliche Beschreibung, das Tutorial und den Beispiel-Download.
Es funktioniert auch alles einwandfrei….
außer… das abspeichern der Unterschrift im IE 11 und auf iOS-Geräten.
Habe Sie diese Problem auch? oder Wissen Sie dafür eine Lösung?
Vielen Dank.
LG
Fabian
Hallo Fabian,
leider habe ich dafür keine Lösung. Der IE11 ist ja eher ein Auslaufmodell und da läuft vieles an neuen Schnickschnack nicht. Apple ist auch so ein Thema für sich. Habe leider kein IOS um das überhaupt zu testen.
Gruß
Andy
Vielen Lieben Dank 🙂
Hallo Andy,
Das Beispiel funktioniert ausgezeichnet. Jetzt habe ich das Problem, dass ich das „entstandene“ Bild beim Speichern nicht im Download-Ordner brauch, sondern in meiner Mysql Datenbank ablegen muß. Gibt es dafür eine nicht zu komplizierte Lösung? Leider habe ich bisher nichts dazu gefunden.
Vielen Dank schon mal für Deine Mühe
Detlef
Hallo,
gute Idee, ich habe daraus einen Blogartikel gemacht:
https://ekiwi.de/index.php/1023/unterschrift-in-mysql-datenbank-speichern-mit-php/
Gruß
Andy
Lieber Andy
Super Erklärung. Hast du ein Tipp, wie ich drei Felder auf derselbenSeite integrieen kann?
Hallo, danke Dir! Meine Empfehlung wäre, Du schaust Dir einfach mal an, wie unsere Software der DA-FormMaker das macht. Wichtig ist, dass die Felder eigene Namen und IDs haben, habe dazu mal ein paar Screenshots erstellt:
https://ekiwi-blog.de/forum/board/thread/50-unterschrift-da-formmaker/
Aber wie gesagt, einfach im DA-FormMaker ausprobieren wie es da vom Code her aussieht.
Danke ich habs hingekriegt
Perfekt! Das freut mich. 🙂
Hi,
kann man in dem Unterschriftsfeld auch ein Hintergrundbild hinterlegen ?
Nein leider ist mir nicht bekannt, dass das einfach so geht.
Gibt es die Möglichkeit eine Validierung einzubauen?
Ich würde schon gerne überprüfen ob eine Unterschrift eingefügt worden ist und nicht nur ein leeres Feld.
Hallo,
ja das geht, unsere Software DA-FormMaker bietet dies auch an. Vielleicht einfach die Software herunterladen und schauen, wie es dort gemacht wird, die Kurzantwort:
if (signaturePad0.isEmpty()) {
alert(„Please enter a value in the field Draw !“);
return false;
Mit der „isEmpty()“ Methode kann man prüfen, ob das Unterschriftenfeld leer ist.
Gruß
Andy
Hallo,
ich weiß nicht, ob hier noch jemand ließt aber falls ja:
Wenn ich die in der Datenbank abgespeicherte Unterschrift später wieder sichtbar machen will,
lade ich es aus der Datenbank und male es mit der Javascript Funktion window.onload
in den zum Canvas gehörigen Kontext:
window.onload = function () {
//alert(„Test“);
var c = document.getElementById(„myCanvas“);
var ctx = c.getContext(„2d“);
var img = document.getElementById(„unterschriftImg“);
ctx.drawImage(img, 0, 0, 350, 150);
}
Aber wenn jetzt de resize Funktion aufgerufen wird, verschwindet die Unterschrift. Wenn ich allerdings in den Canvas hinein male, bleibt das gemalte auch bei resize erhalten. Wie kann man das in den Griff bekommen?
Ja das ist normal, dass bei Größenänderungen das Canvas leer gemacht wird, Du musst es dann neu zeichnen, hier so als grobe Idee:
window.onload = function () {
// Initial draw
drawSignature();
// Redraw on window resize
window.addEventListener(‚resize‘, function() {
drawSignature();
});
};
function drawSignature() {
var c = document.getElementById(„myCanvas“);
var ctx = c.getContext(„2d“);
var img = document.getElementById(„unterschriftImg“);
// Clear the canvas before re-drawing
ctx.clearRect(0, 0, c.width, c.height);
// Draw the image on the canvas
ctx.drawImage(img, 0, 0, 350, 150);
}
Hallo und guten Abend,
ich nutze das Skript für ein Formular, welches am Ende nach dem Absenden in einem PDF geschrieben werden soll. Gibt es eine Lösung, die Daten aus $_POST[„signature“]; entweder in eine Datei auf den Server zu schreiben oder die Daten direkt in ein PDF einzufügen.
Ich nutze FPDF und der Befehl $pdf->Image($_POST[„signature“];,80,267,40);
bringt leider einen Fehler, weil die Daten in $_POST[„signature“]; nicht als Bilddaten erkannt werden.
Was kann ich tun?
GLG
Sascha
P.S.: Vielen Dank für das mega gute Script
Servus Sascha,
ich mache so etwas in der Art bei unserem Formmail-Script. Ich habe die Klasse dafür mal hier online gestellt:
https://gist.github.com/andydunkel/8b98ec3d42486957e9c755ff2492b2ba
Dort ist speichern und so Kram drinnen.
Gruß
Andy