69

Signature

Objective
  • Responder
    • View
      • Signature

Tracez une série de traits continus avec la souris ou un doigt. Appuyez sur la touche Suppr ou cliquez sur la poubelle pour tout effacer.

Déplacez le pointer de la souris en dehors de la zone de dessin. Rechargez la page. Le dessin a été sauvegardé et restauré.

Dans la console du navigateur, récupérez l'image en PNG :

signature.widget.toDataURL()
"data:image/png;base64,iVBORw0KGgoAAAAN...="
  1. function Signature(options = false) {
  2.     options = options || {};
  3.  
  4.     let lineColor = options.lineColor;
  5.     let lineWidth = options.lineWidth;
  6.  
  7.     if (lineColor === undefined)
  8.         lineColor = Signature.defaultLineColor;
  9.     else if (!Validator.validateColor(lineColor))
  10.         throw new TypeError();
  11.  
  12.     if (lineWidth === undefined)
  13.         lineWidth = Signature.defaultLineWidth;
  14.     else if (typeof lineWidth !== 'number')
  15.         throw new TypeError();
  16.  
  17.     View.call(this);
  18.  
  19.     this._lineColor = lineColor;
  20.     this._lineWidth = lineWidth;
  21. }
  22.  
  23. Signature.prototype = Object.create(View.prototype);
  24.  
  25. Object.defineProperty(Signature.prototype, 'constructor', { value: Signature, enumerable: false, writable: true });
  26.  
  27. Signature.defaultLineColor = '#000000';
  28. Signature.defaultLineWidth = 5;

La classe Signature hérite de la classe View. Le constructeur accepte deux options : lineColor, la couleur de la ligne du dessin, et lineWidth, son épaisseur. Par défaut, le trait est noir et son épaisseur est de 5 pixels.

  1. Signature.prototype.erase = function() {
  2.     if (this._widget) {
  3.         this._widget.getContext('2d').clearRect(0, 0, this._widget.width, this._widget.height);
  4.     }
  5.  
  6.     return this;
  7. };

erase efface le widget de this, un canevas, si défini.

  1. Signature.prototype.isBlank = function() {
  2.     if (!this._widget)
  3.         return true;
  4.  
  5.     const imgdata = this._widget.getContext('2d').getImageData(0, 0, this._widget.width, this._widget.height);
  6.  
  7.     return imgdata ? !new Uint32Array(imgdata.data.buffer).some(color => color != 0) : true;
  8. };

isBlank retourne true si this n'a pas de widget ou si le widget, un canevas, n'a pas de contenu, sinon false.

  1. Signature.prototype.setWidget = function(w) {
  2.     if (w.tagName != 'CANVAS')
  3.         throw new TypeError();
  4.  
  5.     if (w.width == 0 || w.height == 0)
  6.         throw new TypeError();

setWidget redéfinit la méthode héritée de la classe View. w, le widget d'une instance de Signature, doit être un canevas.

  1.     View.prototype.setWidget.call(this, w);

Appelle la méthode setWidget héritée de View avec le canevas en argument.

  1.     const ctx = w.getContext('2d');
  2.  
  3.     ctx.strokeStyle = this._lineColor;
  4.     ctx.lineWidth = this._lineWidth;
  5.     ctx.lineJoin = 'round';
  6.     ctx.lineCap = 'round';

Initialise les propriétés de la ligne du dessin dans le contexte du rendu 2D du canevas.

  1.     w.style.touchAction = 'none';

Bloque les interactions par l'utilisateur sur le canevas sur un écran tactile, i.e. un déplacement ou un zoom de l'affichage.

  1.     let x0 = 0;
  2.     let y0 = 0;

x0 et y0 retiennent la dernière position de l'outil de dessin.

  1.     function _stroke(e) {
  2.         if (e.type === 'mousemove' || e.type === 'touchmove')
  3.             return;
  4.  
  5.         let x = e.offsetX * (w.width / w.clientWidth);
  6.         let y = e.offsetY * (w.height / w.clientHeight);
  7.  
  8.         if (x0 && y0) {
  9.             ctx.beginPath();
  10.             ctx.moveTo(x0, y0);
  11.             ctx.lineTo(x, y);
  12.             ctx.stroke();
  13.             ctx.closePath();
  14.         }
  15.  
  16.         x0 = x;
  17.         y0 = y;
  18.     }

La fonction locale _stroke est appelée à chaque fois que l'outil de dessin est déplacé, i.e. à chaque fois qu'un événement mousemove, pointermove ou touchmove est notifié par le canevas. Si l'événement est du type mousemove ou touchmove, la fonction sort immédiatement. Sinon, i.e. l'événement est du type pointermove, la fonction calcule la position du pointeur en tenant compte d'un redimensionnement éventuel du canevas, trace un trait entre la dernière position et la nouvelle position du pointeur, et mémorise la nouvelle position du pointeur.

  1.     w.addEventListener('pointerdown', () => {
  2.         w.addEventListener('pointermove', _stroke, false);
  3.     }, false);
  4.  
  5.     w.addEventListener('pointerup', () => {
  6.         w.removeEventListener('pointermove', _stroke, false), x0 = y0 = 0;
  7.     }, false);
  8.  
  9.     return this;
  10. };

Ajoute la fonction _stroke comme écouteur d'un événement pointermove quand l'utilisateur appuie sur le premier bouton de la souris ou appuie avec un pointeur dans le canevas ou touche le canevas avec un doigt. Retire la fonction _stroke comme écouteur d'un événement pointermove et met la dernière position de l'outil de dessin à 0 si l'utilisateur cesse d'appuyer sur le premier bouton de la souris ou d'appuyer sur le canevas ou de toucher le canevas.

Test
  1. <?php $bg='#ffc'; ?>
  2. <?php $width=600; ?>
  3. <?php $height=400; ?>
  4. <?php $linewidth=5; ?>
  5. <?php $linecolor='#00f'; ?>
  6. <?php $trashcolor='#e02'; ?>

Définit la couleur de fond, la largeur et la hauteur de la zone de dessin, l'épaisseur et la couleur du trait, la couleur de la poubelle.

  1. <?php $id=uniqid('id'); ?>

Définit l'identifiant de la <div> qui encadre l'affichage de test.

  1. .test_display {
  2.     display: inline-block;
  3.     position: relative;
  4.     margin: 1em 0 0;
  5. }
  6. .test_display canvas {
  7.     background-color: <?php echo $bg; ?>;
  8. }
  9. .test_display i.fa-trash {
  10.     position: absolute; bottom: 10px; right: 5px;
  11.     padding: 10px; border-radius: 50%; background-color: #fff;
  12.     color: <?php echo $trashcolor; ?>;
  13.     cursor: pointer;
  14. }

Configure l'apparence de la zone de dessin. Place la poubelle en bas à droite.

  1. <div id="<?php echo $id; ?>" class="noprint">
  2. <div class="test_display">
  3. <canvas width="<?php echo $width; ?>" height="<?php echo $height; ?>"></canvas>
  4. <i class="fas fa-trash"></i>
  5. </div>
  6. </div>

Crée la <div> de l'affichage de test avec un canevas et l'image d'un bouton.

  1. <?php head('javascript', '/objectivejs/Objective.js'); ?>
  2. <?php head('javascript', '/objectivejs/Responder.js'); ?>
  3. <?php head('javascript', '/objectivejs/View.js'); ?>
  4. <?php head('javascript', '/objectivejs/Validator.js'); ?>
  5. <?php head('javascript', '/objectivejs/Signature.js'); ?>

Inclut le code de toutes les classes nécessaires. RAPPEL : La fonction head de la librairie iZend ajoute une balise telle que <script src="/objectivejs/Objective.js"></script> à la section <head> du document HTML. Adaptez le code à votre environnement de développement.

  1. const signature = new Signature({lineColor: '<?php echo $linecolor; ?>', lineWidth: <?php echo $linewidth; ?>});
  2.  
  3. const container = document.querySelector('#<?php echo $id; ?>');
  4.  
  5. signature.setManagedWidget(container.querySelector('canvas'));

Crée une instance de Signature et configure son widget, le canevas.

  1. const trash = container.querySelector('i.fa-trash');
  2.  
  3. trash.onclick = () => signature.erase();

Efface la signature si on clique sur la poubelle.

  1. signature.setAttribute('tabindex', 0);
  2.  
  3. signature.addEventListener('keydown', (e) => {
  4.     if (e.key === 'Delete')
  5.         signature.erase();
  6. });

Efface la signature si on appuie sur la touche Suppr dans le canevas.

  1. const storage = sessionStorage;

Accède à l'espace de stockage de la page.

  1. const url = storage.getItem('signature');
  2.  
  3. if (url !== null) {
  4.     const img = new Image();
  5.  
  6.     img.onload = () => signature.widget.getContext('2d').drawImage(img, 0, 0);
  7.     img.src = url;
  8. }

Si une URL data a été sauvegardée dans l'espace de stockage, affiche l'image qu'elle contient dans le canevas.

  1. signature.addEventListener('mouseout', () => storage.setItem('signature', signature.widget.toDataURL()));

Sauvegarde l'image dessinée dans le canevas dans l'espace de stockage quand le pointeur quitte la zone de dessin.

VOIR AUSSI

View, Drawingarea, Validator

Commentaires

Votre commentaire :
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip aide 2000

Entrez un maximum de 2000 caractères.
Améliorez la présentation de votre texte avec les balises de formatage suivantes :
[p]paragraphe[/p], [b]gras[/b], [i]italique[/i], [u]souligné[/u], [s]barré[/s], [quote]citation[/quote], [pre]tel quel[/pre], [br]à la ligne,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]commande[/code], [code=langage]code source en c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].