29 กรกฎาคม 2562

Signature Pad draw on browser

เซ็นชื่อบนหน้าจอ แล้วเซฟเก็บไว้ ?

หลายๆ คนคงเจอมากับตัวเองบ้างแล้ว กับลายมือชื่ออิเล็กทรอนิกส์ (Electronic signature) ที่เป็นการเซ็นลงไปบนอุปกรณ์ elctronic โดยตรง แทนที่การเซ็นลงบนกระดาษ ซึ่งเบื้องต้น ต้องขออธิบายก่อน ว่าการรับรองเอกสารทางอิเล็กทรอนิกส์ แบ่งได้สองประเภทคือ
  • Electronic Signature : เป็นการเขียนบนหน้าจอตรงๆ (ไม่ว่าจะเป็นนิ้ว หรือปากกา stylus) หรือเซฟเป็นภาพเอาไว้แล้ว มาตัดแปะลงบนกระดาษ ซึ่งมีความน่าเชื่อถือต่ำ เพราะสามารถรีทัช ดัดแปลงได้
  • Digital Signature : จะมีความน่าเชื่อถือมากกว่า Electronic Signature โดยจะเพิ่มในส่วนของผู้รับรองเข้ามา (CA หรือ Certificate Authority) เป็นตัวกลางอีกขึ้นหนึ่ง ซึ่งข้อมูลของการยืนยันตัวตัว จะถูกเข้ารหัสเอาไว้ ไม่สามารถเปลี่ยนแปลงได้ โดยอาจจะเป็นข้อมูลตั้งต้นมาจากคอมพิวเตอร์ล้วนๆ หรืออาจจะนำเข้าข้อมูลชีวภาพ เช่นสแกนลายนิ้วมือมาจัดเก็บเป็นข้อมูล ก่อนนำไปเข้ารหัสก็ได้
ในส่วนของด้านกฏหมาย ทาง blog คงไม่ขอลงรายละเอียด เนื่องจากผู้เขียน เป็นสาย dev แต่เนื่องจากผู้เขียน พบการใช้งานจริงมากขึ้นไม่ว่าจะกับการเซ็นรับพัสดุไปรษณีย์ หรือเซ็นชื่อจ่ายบัตรเครดิตตามห้างสรรพสินค้า ซึ่งแม้จะขยุกขยุยเขียนได้ไม่คมชัดเท่ากับ กระดาษปากกา แต่ก็น่าจะเป็นที่ยอมรับในทางกฏหมายอยู่ระดับนึง หรือว่าอาจจะนำมาใช้งานวาดรูปเล่น เขียน short note แทน ก็แล้วแต่การนำไปประยุกต์ใช้งาน
เกริ่นมานานพอสมควร สำหรับคนเขียนเว็บทั่วๆ ไป ก็คงถือว่าเป็นงานยากไม่น้อย หากจะเขียนโปรแกรมให้เขียนบนหน้าจอได้ ก็เลยถึงเวลาแนะนำพระเอกของเรา szimek signature_pad ซึ่งเป็น JavaScript library ที่ใช้ HTML5 canvas เป็นแกนหลัก ซึ่งสามารถแสดงผลได้ใน browser ใหม่ๆ รองรับทั้ง version desktop และ mobile อ่านเพิ่มเติม เกี่ยวกับ HTML5 canvas ซึ่งทางผมยังไม่ได้ทดสอบการใช้งานกับตัวอื่นๆ แต่สำหรับ Chrome ที่นิยมสำหรับ user ทั่วไปแล้ว สามารถใช้งานได้เป็นอย่างดีครับ ทั้ง Desktop และ Mobile

Installation

มาเริ่มต้นติดตั้งใช้งานกัน สามารถติดตั้งได้ทั้งทาง npm yarn หรือเรียกใช้ library โดยตรงจาก cdn ในตัวอย่างนี้ ขอเรียกใช้ผ่าน cdn นะครับ

<script src="https://cdn.jsdelivr.net/npm/signature_pad@3.0.0-beta.3/dist/signature_pad.min.js"></script>

Basic Sample

จากนั้น ก็ประกาศใช้ canvas ขึ้นมาดื้อๆ ใน html ได้เลยครับ ใส่ border นิดนึงเพื่อให้ดูง่าย

<canvas id="myCanvas" width="400" height="200" style="border:1px solid #000000;"></canvas>

แล้วในส่วนของ javascript ก็เรียกใช้กันแบบ DOM ดื้อๆ ได้เลย (จะประยุกต์ใช้ jquery ก็แล้วแต่ความสะดวกของแต่ละคน)

    var canvas = document.getElementById("myCanvas");
    var signaturePad = new SignaturePad(canvas);

เสร็จแล้วครับ เพียงแค่นี้ เราก็ได้กระดานลายเซ็นขนาด 400x200 แบบง่ายๆ แล้ว จะเซ็น จะวาด ก็ตามใจเราเลยครับ


Advance Sample

แน่นอนว่า วาดเล่นได้แค่นั้น มันยังไม่ตอบโจทย์การใช้งานจริงแน่นอนครับ เรามาปรับแต่งกันต่อ เขียนเสร็จแล้ว ตัวอย่างที่จะแสดงคือ
  • Clear : กระดานเริ่มใหม่
  • Undo : ย้อนกลับ การวาดครั้งหลังสุด
  • Red Color : เปลี่ยนสีปากกาจากดำเป็นแดง
  • Export : บันทึกเป็นไฟล์ png
ฝั่ง html ก็เพิ่มปุ่มกับการเรียก javascript function แบบง่ายๆ ไปได้เลยครับ
<button type="button" onClick="clearCanvas()">Clear</button>
<button type="button" onClick="undoCanvas()">Undo</button>
<button type="button" onClick="redCanvas()">Red Color</button>
<button type="button" onClick="exportCanvas()">Export</button>

ตามด้วย script จับคู่กับ 4 ปุ่มข้างต้น โดย 3 ปุ่มแรก จะเรียกแค่ function ของ library ตรงๆ เข้าใจง่ายๆ แต่ในส่วนของการเซฟ png จะซับซ้อนนิดนึง เป็นการเซฟ data แบบ binary ซึ่งสามารถ copy ไปแปะเอาได้เลย
    function clearCanvas() {
      signaturePad.clear();
    }

    function undoCanvas() {
      var data = signaturePad.toData();

      if (data) {
        data.pop(); // remove the last dot or line
        signaturePad.fromData(data);
      }
    }

    function redCanvas() {
      signaturePad.penColor = "rgb(255,0,0)";
    }

    function exportCanvas() {
      if (signaturePad.isEmpty()) {
        alert("Draw something");
      } else {
        var dataURL = signaturePad.toDataURL();
        download(dataURL, "signature.png");
      }
    }

    function download(dataURL, filename) {
      if (navigator.userAgent.indexOf("Safari") > -1 && navigator.userAgent.indexOf("Chrome") === -1) {
        window.open(dataURL);
      } else {
        var blob = dataURLToBlob(dataURL);
        var url = window.URL.createObjectURL(blob);

        var a = document.createElement("a");
        a.style = "display: none";
        a.href = url;
        a.download = filename;

        document.body.appendChild(a);
        a.click();

        window.URL.revokeObjectURL(url);
      }
    }

    // One could simply use Canvas#toBlob method instead, but it's just to show
    // that it can be done using result of SignaturePad#toDataURL.
    function dataURLToBlob(dataURL) {
      // Code taken from https://github.com/ebidel/filer.js
      var parts = dataURL.split(';base64,');
      var contentType = parts[0].split(":")[1];
      var raw = window.atob(parts[1]);
      var rawLength = raw.length;
      var uInt8Array = new Uint8Array(rawLength);

      for (var i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i);
      }

      return new Blob([uInt8Array], { type: contentType });
    }

เสร็จแล้วครับ แค่นี้เราก็จะได้กระดานวาดภาพอย่างง่าย จะวาด จะเซ็น จะเปลี่ยนสี จะบันทึก ก็ทำได้เรียบร้อยแล้ว

ยังสามารถปรับแต่งได้เพิ่มเติมจากตัวอย่างที่ผมเขียนมา เช่นการเปลี่ยนพื้นหลัง การลบ การปรับขนาด สามารถไปศึกษาเพิ่มเติมได้จากต้นทางคือ szimek signature_pad ซึ่งอาจจะมีการเชื่อมโยงไฟล์หลายไฟล์ มีการปรับ css โครงสร้างเพื่อความสวยงาม แต่ทางผมจะเน้นพื้นฐานการอ่าน code ให้เข้าใจ แล้วสามารถแปล และทำงานได้ครบ จบใน 1 ไฟล์ สามารถ copy จาก code snippet ไปใช้งานได้เลยครับ เมื่อมีความเข้าใจแล้ว ก็แล้วแต่ แต่ละคนจะนำไปประยุกต์ใช้งานกันต่อไปครับ

Full code snippet

สามารถบันทึกเป็น .html แล้วเปิดเรียกทดสอบได้เลยครับ

ไม่มีความคิดเห็น:

แสดงความคิดเห็น