Criar um componente para colher assinatura Olá amigos, Tenho a necessidade de colher assinaturas de solicitantes em dispositivos móveis como tablet ou celular, até achei um bom exemplo que responde bem, mas não consigo integra-lo com o Adianti. Será que alguém sabe como fazer ? Abaixo deixo o HTML que é exemplo. ...
FA
Criar um componente para colher assinatura  
Olá amigos,

Tenho a necessidade de colher assinaturas de solicitantes em dispositivos móveis como tablet ou celular, até achei um bom exemplo que responde bem, mas não consigo integra-lo com o Adianti. Será que alguém sabe como fazer ?
Abaixo deixo o HTML que é exemplo.

<!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="utf-8"/> <title></title> <style> .wrapper { position: relative; width: 250px; height: 367px; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; } img { position: absolute; left: 0; top: 0; } .signature-pad { position: absolute; left: 0; top: 0; width:250px; height:367px; } </style> </head> <body> <div class="wrapper"> <img src="Hatch.jpg" width=250 height=367 /> <canvas id="signature-pad" class="signature-pad" width=250 height=367></canvas> </div> <div> <button id="save">Save</button> <button id="clear">Clear</button> </div> <form action=""> <textarea name="" id="imageCheck" cols="30" rows="10"></textarea> </form> </body> <script src="https://cdn.jsdelivr.net/npm/signature_pad@3.0.0-beta.3/dist/signature_pad.min.js"></script> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=" crossorigin="anonymous"></script> <script> 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); } } 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 }); } var signaturePad = new SignaturePad(document.getElementById('signature-pad'), { backgroundColor: 'rgba(255, 255, 255, 0)', penColor: 'rgb(0, 0, 0)' }); var saveButton = document.getElementById('save'); var cancelButton = document.getElementById('clear'); saveButton.addEventListener("click", function(event) { if (signaturePad.isEmpty()) { alert("Faça sua assinatura."); } else { var dataURL = signaturePad.toDataURL(); //download(dataURL, "signature.png"); //alert(dataURL); $("#imageCheck").val(dataURL); } }); cancelButton.addEventListener('click', function(event) { signaturePad.clear(); }); </script> </html>

Curso Dominando o Adianti Framework

O material mais completo de treinamento do Framework.
Curso em vídeo aulas + Livro completo + Códigos fontes do projeto ERPHouse.
Conteúdo Atualizado!


Dominando o Adianti Framework Quero me inscrever agora!

Comentários (9)


MA

Bom dia, você precisa criar um componente, não irei criar completo pela a falta de tempo, mas dentro de libwidgets da app tem exemplo pra você criar seus próprios componentes.
De maneira grosseira de organização de codigos você pode criar algo asssim

 
  1. <?php
  2. /**
  3. * Class TSignaturePad
  4. * @author Marcelo Alves
  5. * 5/31/20 11:43 AM
  6. */
  7. use Adianti\Widget\Base\TElement;
  8. use Adianti\Widget\Form\AdiantiWidgetInterface;
  9. use Adianti\Widget\Form\TField;
  10. class TSignaturePad extends TField implements AdiantiWidgetInterface
  11. {
  12. protected $id;
  13. protected $formName;
  14. protected $size;
  15. protected $height;
  16. /**
  17. * Class Constructor
  18. * @param $name Widet's name
  19. */
  20. public function __construct($name)
  21. {
  22. parent::__construct($name);
  23. $this->id = 'signature-pad'; // . mt_rand(1000000000, 1999999999);
  24. // creates a <canvas> tag
  25. $this->tag = new TElement('canvas');
  26. $this->tag->{'class'} = 'signature-pad'; // CSS
  27. $this->tag->{'widget'} = 'signature_pad';
  28. // defines the text default height
  29. $this->width = 400;
  30. $this->height = 200;
  31. echo "<style>
  32. .wrapper-signature-pad {
  33. position: relative;
  34. width: 400px;
  35. height: 200px;
  36. -moz-user-select: none;
  37. -webkit-user-select: none;
  38. -ms-user-select: none;
  39. user-select: none;
  40. }
  41. .signature-pad {
  42. position: absolute;
  43. left: 0;
  44. top: 0;
  45. width:400px;
  46. height:200px;
  47. }
  48. </style>";
  49. }
  50. /**
  51. * Define the widget's size
  52. * @param $width Widget's width
  53. * @param $height Widget's height
  54. */
  55. public function setSize($width, $height = NULL)
  56. {
  57. $this->size = $width;
  58. if ($height) {
  59. $this->height = $height;
  60. }
  61. }
  62. /**
  63. * Returns the size
  64. * @return array(width, height)
  65. */
  66. public function getSize()
  67. {
  68. return array($this->size, $this->height);
  69. }
  70. /**
  71. * Show the widget
  72. */
  73. public function show()
  74. {
  75. $this->tag->{'name'} = $this->name;
  76. if ($this->size) {
  77. $size = (strstr($this->size, '%') !== FALSE) ? $this->size : "{$this->size}px";
  78. $this->setProperty('style', "width:{$size};", FALSE);
  79. }
  80. if ($this->height) {
  81. $height = (strstr($this->height, '%') !== FALSE) ? $this->height : "{$this->height}px";
  82. $this->setProperty('style', "height:{$height}", FALSE);
  83. }
  84. if ($this->id and empty($this->tag->{'id'})) {
  85. $this->tag->{'id'} = $this->id;
  86. }
  87. $container = TElement::tag("div", $this->tag);
  88. $container->class = "wrapper-signature-pad";
  89. $container->show();
  90. \Adianti\Widget\Base\TScript::create("
  91. var signaturePad = new SignaturePad(document.getElementById('signature-pad'), {
  92. backgroundColor: 'rgba(255, 255, 255, 0)',
  93. penColor: 'rgb(0, 0, 0)'
  94. });
  95. ");
  96. }
  97. }
  98. ?>


Coloquei a biblioteca https://cdn.jsdelivr.net/npm/signature_pad@3.0.0-beta.3/dist/signature_pad.umd.min.js nas libs do projeto e obtive o resultado.

Resultado aqui: https://ibb.co/QD5DmhZ</canvas>
FA

Boa Noite Marcelo,

Cara, era bem isso que estava precisando, tinha me esquecido completamente da capacidade do Adianti criar novos componentes. Bem, todavia eu preciso salvar a imagem, assim tive de fazer alguns ajustes para tanto.

Acrescentei algumas boxes para poder dispor dos botões de salvar e limpar o campo, além disto criei um método que retorna onde a imagem foi salva sendo o $componente->getImage().

Mas nem tudo está perfeito pois não estou conseguindo redimensionar de forma satisfatória usando o comando $componente->setSize(X,Y), se puder me ajudar fico muito grato.

 
  1. <?php
  2. /**
  3. * Class TSignaturePad
  4. * @author Marcelo Alves
  5. * @coauthor Fernando de Pinho Araújo
  6. * 5/31/20 11:43 AM
  7. * path app/lib/widget
  8. */
  9. use Adianti\Widget\Base\TElement;
  10. use Adianti\Widget\Form\AdiantiWidgetInterface;
  11. use Adianti\Widget\Form\TField;
  12. class TSignaturePad extends TField implements AdiantiWidgetInterface
  13. {
  14. protected $id;
  15. protected $formName;
  16. protected $size;
  17. protected $height;
  18. /**
  19. * Class Constructor
  20. * @param $name Widet's name
  21. */
  22. public function __construct($name)
  23. {
  24. parent::__construct($name);
  25. $this->id = 'signature-pad';// . mt_rand(1000000000, 1999999999);
  26. // creates a <canvas> tag
  27. $this->tag = new TElement('canvas');
  28. $this->tag->{'class'} = 'signature-pad';
  29. $this->tag->{'widget'} = 'signature_pad';
  30. // defines the text default height
  31. $this->width = 400;
  32. $this->height = 200;
  33. echo "<style>
  34. .wrapper-signature-pad {
  35. position: relative;
  36. width: 400px;
  37. height: 200px;
  38. -moz-user-select: none;
  39. -webkit-user-select: none;
  40. -ms-user-select: none;
  41. user-select: none;
  42. }
  43. .signature-pad {
  44. position: absolute;
  45. left: 0;
  46. top: 0;
  47. width:400px;
  48. height:200px;
  49. }
  50. </style>";
  51. }
  52. /**
  53. * Define the widget's size
  54. * @param $width Widget's width
  55. * @param $height Widget's height
  56. */
  57. public function setSize($width, $height = NULL)
  58. {
  59. $this->size = $width;
  60. if ($height) {
  61. $this->height = $height;
  62. }
  63. }
  64. /**
  65. * Returns the size
  66. * @return array(width, height)
  67. */
  68. public function getSize()
  69. {
  70. return array($this->size, $this->height);
  71. }
  72. /**
  73. * Show the widget
  74. */
  75. public function show()
  76. {
  77. $this->tag->{'name'} = $this->name;
  78. if ($this->size) {
  79. $size = (strstr($this->size, '%') !== FALSE) ? $this->size : "{$this->size}px";
  80. $this->setProperty('style', "width:{$size};", FALSE);
  81. }
  82. if ($this->height) {
  83. $height = (strstr($this->height, '%') !== FALSE) ? $this->height : "{$this->height}px";
  84. $this->setProperty('style', "height:{$height}", FALSE);
  85. }
  86. if ($this->id and empty($this->tag->{'id'})) {
  87. $this->tag->{'id'} = $this->id;
  88. }
  89. //Função para Salvar o desenho
  90. $save = new TButton('save');
  91. $save->setId('save_signature');
  92. $save->setImage('fas:save red');
  93. $save->class = 'btn btn-default';
  94. $save->style = "
  95. position: absolute;
  96. top: 0;
  97. ";
  98. $save->title = 'Armazena';
  99. $save->addFunction("
  100. var canvas = document.getElementById('signature-pad');
  101. var dataURL = canvas.toDataURL();
  102. $.ajax({
  103. type: \"POST\",
  104. url: \"get_signature.php\",
  105. data: {
  106. imgBase64: dataURL,
  107. toName:" . TSession::getValue('login') . "
  108. }
  109. }).done(function(o) {
  110. alert('Assinatura Salva');
  111. }); ");
  112. //Função para Limpar o desenho
  113. $clear = new TButton('clear');
  114. $clear->setId('clear_signature');
  115. $clear->setImage('far:trash-alt blue');
  116. $clear->class = 'btn btn-default';
  117. $clear->style = "
  118. position: absolute;
  119. top: 32px;
  120. ";
  121. $clear->title = 'Limpa';
  122. $clear->addFunction("
  123. var signaturePad = new SignaturePad(document.getElementById('signature-pad'), {
  124. backgroundColor: 'rgba(255, 255, 255, 0)',
  125. penColor: 'rgb(0, 0, 0)'
  126. });");
  127. // vertical box container
  128. $vbox = new TVBox;
  129. $vbox->style = "width: 100%";
  130. $vbox->add($save);
  131. $vbox->add($clear);
  132. $div = TElement::tag("div", $this->tag);
  133. $div->class = "wrapper-signature-pad";
  134. $hbox = new THBox;
  135. $hbox->addRowSet( $div, $vbox );
  136. $container = TElement::tag('div',$hbox);
  137. $container->style = 'width: 100%';
  138. $container->height = $this->height + $hbox->getProperty('height') + 64;
  139. $container->show();
  140. \Adianti\Widget\Base\TScript::create("
  141. var signaturePad = new SignaturePad(document.getElementById('signature-pad'), {
  142. backgroundColor: 'rgba(255, 255, 255, 0)',
  143. penColor: 'rgb(0, 0, 0)'
  144. });
  145. ");
  146. $this->clearImage();
  147. }//Fim Método
  148. /**
  149. * Retorna o endereço onde está a imagem
  150. **/
  151. public static function getImage($param)
  152. {
  153. define('UPLOAD_DIR', 'tmp/');
  154. $name = TSession::getValue('login');
  155. $file = UPLOAD_DIR . $name . '_signature.png';
  156. }//Fim Método
  157. /**
  158. * Retorna o endereço onde está a imagem
  159. **/
  160. public function clearImage($param = null)
  161. {
  162. define('UPLOAD_DIR', 'tmp/');
  163. $name = TSession::getValue('login');
  164. $file = UPLOAD_DIR . $name . '_signature.png';
  165. //Se o arquivo já existe, apaga
  166. if (file_exists($file))
  167. {
  168. unlink($file);
  169. }
  170. }
  171. }//Fim Classe
  172. </code>


Baixo o arquivo que salva no servidor os dados oriundos do componente.

 
  1. <?php
  2. /**
  3. * get_signature.php
  4. * Carrega uma assinatura e armazena na pasta /tmp
  5. * @author Fernando de Pinho Araújo
  6. * 2020/06/01
  7. * path raiz
  8. */
  9. require_once 'init.php';
  10. new TSession;
  11. if ( TSession::getValue('logged') )
  12. {
  13. // requires php5
  14. define('UPLOAD_DIR', 'tmp/');
  15. $img = $_POST['imgBase64'] ?? false;
  16. $name = $_POST['toName'] ?? false;
  17. //Verifica se existe dados a salvar
  18. if ($img && $name)
  19. {
  20. $img = str_replace('data:image/png;base64,', '', $img);
  21. $img = str_replace(' ', '+', $img);
  22. $data = base64_decode($img);
  23. $file = UPLOAD_DIR . $name . '_signature.png';
  24. //Se o arquivo já existe, apaga
  25. if (file_exists($file))
  26. {
  27. unlink($file);
  28. }
  29. $success = file_put_contents($file, $data);
  30. }
  31. }
  32. </code>
</canvas>
FA

Ainda penso que seria interessante fazer a carga da assinatura anterior dentro do próprio canvas, mas da forma que já está ficou muito bom.
R

Estou tentando fazer funcionar este código e não consigo há alguma possibilidade de me ajduar?
FA

Podemos conversar sim...
R

pode me mandar um whatss (41)991019337
R

eu escrevi o Código conforme acima mais não salvou a imagem na pasta tmp

estou parado com e erro na linha 12
]
FA

Me chama no zap 62 992447470
DA

Olá Fernando

Estou criando uma aplicação de Checklist e para finalizar preciso pegar as assinaturas, vi esse post no Fórum e tentei utilizá-lo, até cheguei a fazer com que ele mostrasse na tela, os botões de salvar e limpar, porém não escreve, na vez que consegui fazer com que escrevesse ficou perdido a assinatura pela página.

Com não tenho muito experiência na programação web, estou tentando desmamar do Delphi, e escolhi o Adianti para isso. Tenho evoluído em cima de exemplos, teria algum exemplo da chamada do componente, tentei colocar numa TWindow aparece bonitinho mas não funciona, na TPage até chegou a funcionar , porém ficou da forma que comentei acima.

Ficarei agradecido se puder me auxiliar nesse probleminha.

Tentei chamar assim para testar o componente, não sei se é o correto, colocando TWindow visualiza melhor, com TPage os botões ficam escondidos.

 
  1. <?php
  2. class Assinatura extends TPage
  3. {
  4. public function __construct()
  5. {
  6. parent::__construct();
  7. $assina = new TSignaturePad('assina');
  8. parent::add($assina);
  9. }
  10. }
  11. ?>