signature.html.twig 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. {% extends "forms/field.html.twig" %}
  2. {% block prepend %}
  3. <div id="signature-pad" class="signature-pad">
  4. <div class="signature-pad--body">
  5. <canvas></canvas>
  6. </div>
  7. <div class="signature-pad--footer">
  8. <div class="description">Sign above</div>
  9. <div class="signature-pad--actions">
  10. <div>
  11. <button type="button" class="btn btn-primary-border" data-action="clear">Clear Signature</button>
  12. </div>
  13. </div>
  14. </div>
  15. </div>
  16. <script src="{{ url('plugin://form/assets/signature_pad.js') }}"></script>
  17. <script>
  18. var wrapper = document.getElementById("signature-pad");
  19. var clearButton = wrapper.querySelector("[data-action=clear]");
  20. var canvas = wrapper.querySelector("canvas");
  21. var signaturePad = new SignaturePad(canvas, {
  22. // It's Necessary to use an opaque color when saving image as JPEG;
  23. // this option can be omitted if only saving as PNG or SVG
  24. backgroundColor: 'rgb(255, 255, 255)',
  25. onEnd: function() {
  26. var input = document.querySelector('[name="data[{{ field.name }}]"]');
  27. input.value = this.toDataURL();
  28. }
  29. });
  30. // Adjust canvas coordinate space taking into account pixel ratio,
  31. // to make it look crisp on mobile devices.
  32. // This also causes canvas to be cleared.
  33. function resizeCanvas() {
  34. // When zoomed out to less than 100%, for some very strange reason,
  35. // some browsers report devicePixelRatio as less than 1
  36. // and only part of the canvas is cleared then.
  37. var ratio = Math.max(window.devicePixelRatio || 1, 1);
  38. // This part causes the canvas to be cleared
  39. canvas.width = canvas.offsetWidth * ratio;
  40. canvas.height = canvas.offsetHeight * ratio;
  41. canvas.getContext("2d").scale(ratio, ratio);
  42. // This library does not listen for canvas changes, so after the canvas is automatically
  43. // cleared by the browser, SignaturePad#isEmpty might still return false, even though the
  44. // canvas looks empty, because the internal data of this library wasn't cleared. To make sure
  45. // that the state of this library is consistent with visual state of the canvas, you
  46. // have to clear it manually.
  47. signaturePad.clear();
  48. }
  49. // On mobile devices it might make more sense to listen to orientation change,
  50. // rather than window resize events.
  51. window.onresize = resizeCanvas;
  52. resizeCanvas();
  53. function download(dataURL, filename) {
  54. var blob = dataURLToBlob(dataURL);
  55. var url = window.URL.createObjectURL(blob);
  56. var a = document.createElement("a");
  57. a.style = "display: none";
  58. a.href = url;
  59. a.download = filename;
  60. document.body.appendChild(a);
  61. a.click();
  62. window.URL.revokeObjectURL(url);
  63. }
  64. // One could simply use Canvas#toBlob method instead, but it's just to show
  65. // that it can be done using result of SignaturePad#toDataURL.
  66. function dataURLToBlob(dataURL) {
  67. // Code taken from https://github.com/ebidel/filer.js
  68. var parts = dataURL.split(';base64,');
  69. var contentType = parts[0].split(":")[1];
  70. var raw = window.atob(parts[1]);
  71. var rawLength = raw.length;
  72. var uInt8Array = new Uint8Array(rawLength);
  73. for (var i = 0; i < rawLength; ++i) {
  74. uInt8Array[i] = raw.charCodeAt(i);
  75. }
  76. return new Blob([uInt8Array], { type: contentType });
  77. }
  78. clearButton.addEventListener("click", function (event) {
  79. signaturePad.clear();
  80. });
  81. </script>
  82. {% endblock prepend %}
  83. {% block input_attributes %}
  84. type="hidden"
  85. {{ parent() }}
  86. {% endblock %}