Lançado Adianti Framework 8.1!
Clique aqui para saber mais
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.         
  88.         $container TElement::tag("div"$this->tag);
  89.         $container->class =  "wrapper-signature-pad";
  90.         $container->show();
  91.         \Adianti\Widget\Base\TScript::create("
  92.              var signaturePad = new SignaturePad(document.getElementById('signature-pad'), {
  93.              backgroundColor: 'rgba(255, 255, 255, 0)',
  94.              penColor: 'rgb(0, 0, 0)'
  95.           });
  96.         
  97.         ");
  98.     }
  99. }
  100. ?>


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.         
  90.         //Função para Salvar o desenho
  91.         $save  = new TButton('save');
  92.         $save->setId('save_signature');
  93.         $save->setImage('fas:save red');        
  94.         $save->class 'btn btn-default';
  95.         $save->style "
  96.                           position: absolute;
  97.                           top: 0;
  98.         ";
  99.         $save->title 'Armazena';
  100.         $save->addFunction("
  101.                             var canvas = document.getElementById('signature-pad');
  102.                             
  103.                             var dataURL = canvas.toDataURL();
  104.                         
  105.                         $.ajax({
  106.                           type: \"POST\",
  107.                           url: \"get_signature.php\",
  108.                           data: { 
  109.                              imgBase64: dataURL,
  110.                              toName:" TSession::getValue('login') . "
  111.                              
  112.                           }
  113.                         }).done(function(o) {
  114.                           alert('Assinatura Salva'); 
  115.                         
  116.                         }); ");
  117.         //Função para Limpar o desenho
  118.         $clear = new TButton('clear');
  119.         $clear->setId('clear_signature');
  120.         $clear->setImage('far:trash-alt blue');
  121.         $clear->class 'btn btn-default';
  122.         $clear->style "
  123.                           position: absolute;
  124.                           top: 32px;
  125.         ";
  126.         $clear->title 'Limpa';
  127.         $clear->addFunction("
  128.                              var signaturePad = new SignaturePad(document.getElementById('signature-pad'), {
  129.                              backgroundColor: 'rgba(255, 255, 255, 0)',
  130.                              penColor: 'rgb(0, 0, 0)'
  131.                           });");
  132.         
  133.         
  134.         // vertical box container
  135.         $vbox        = new TVBox;
  136.         $vbox->style "width: 100%";
  137.         $vbox->add($save);
  138.         $vbox->add($clear);
  139.         
  140.         $div TElement::tag("div"$this->tag);
  141.         $div->class  =  "wrapper-signature-pad";
  142.         $hbox = new THBox;
  143.         $hbox->addRowSet$div$vbox );
  144.         
  145.         $container        TElement::tag('div',$hbox);
  146.         $container->style 'width: 100%';
  147.         $container->height $this->height $hbox->getProperty('height') + 64;        
  148.         
  149.         $container->show();
  150.         \Adianti\Widget\Base\TScript::create("
  151.              var signaturePad = new SignaturePad(document.getElementById('signature-pad'), {
  152.              backgroundColor: 'rgba(255, 255, 255, 0)',
  153.              penColor: 'rgb(0, 0, 0)'
  154.           });
  155.         ");
  156.         $this->clearImage();
  157.     }//Fim Método
  158. /**
  159.  * Retorna o endereço onde está a imagem
  160.  **/
  161.     public static function getImage($param)
  162.     {
  163.         define('UPLOAD_DIR''tmp/');
  164.         $name TSession::getValue('login');
  165.           $file UPLOAD_DIR $name '_signature.png';
  166.     }//Fim Método
  167. /**
  168.  * Retorna o endereço onde está a imagem
  169.  **/
  170.     public function clearImage($param null)
  171.     {
  172.         define('UPLOAD_DIR''tmp/');
  173.         $name TSession::getValue('login');
  174.           $file UPLOAD_DIR $name '_signature.png';
  175.         //Se o arquivo já existe, apaga
  176.         if (file_exists($file))
  177.         {
  178.              unlink($file);
  179.         }
  180.     }
  181. }//Fim Classe
  182. </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.     
  5.     public function __construct()
  6.     {
  7.     
  8.       parent::__construct();
  9.       $assina = new TSignaturePad('assina');
  10.     
  11.       parent::add($assina);          
  12.     
  13.     }
  14. }
  15. ?>