189

Signature

Objective
  • Responder
    • View
      • Signature

Draw a series of continuous lines with the mouse or a finger. Press the Del key or click on the trash can to erase everything.

Move the pointer of the mouse outside the drawing area. Reload the page. The drawing was saved and restored.

In the console of the navigator, retrieve the image in 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;

The Signature class inherits from the View class. The constructor accepts two options : lineColor, the color of the drawing line, and lineWidth, its thickness. By default, the drawing line is black with a thickness of 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 erases the widget of the view, a canvas, if defined.

  1. Signature.prototype.setWidget = function(w) {
  2.     if (w.tagName != 'CANVAS')
  3.         throw new TypeError();

setWidget redefines the method inherited from the View class. w, the widget of an instance of a Signature, must be a canvas.

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

Calls the method setWidget inherited from View with the canvas in 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';

Initializes the properties of the drawing line in the 2D rendering context of the canvas.

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

Blocks interactions by the user on the canvas on a touchscreen , I.e moving or zooming the display.

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

x0 and y0 hold the last position of the drawing tool.

  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.     };

The local function _stroke is called every time the drawing tool is moved, i.e. every time a mousemove, a pointermove or a touchmove event is notified by the canvas. If the event is of the type mousemove or touchmove, the function exits immediately. Otherwise, i.e. the event is of the type pointermove, the function calculates the position of the pointer taking into account a possible resizing of the canvas, draws a line between the last position and the new position of the pointer, and memorizes the new position of the pointer.

  1.     w.addEventListener('mousedown', () => {
  2.         if (event.which === 1)
  3.             w.addEventListener('mousemove', _stroke, false);
  4.     }, false);
  5.  
  6.     w.addEventListener('mouseup', () => {
  7.         if (event.which === 1)
  8.             w.removeEventListener('mousemove', _stroke, false), x0 = y0 = 0;
  9.     }, false);

Adds the function _stroke as a listener to the event mousemove notified by the canvas when the user presses on the first button of the mouse in the canvas. Removes the function _stroke as a listener to the event mousemove when the user stops pressing the first button of the mouse in the canvas and sets the last position of the drawing tool to 0.

  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);

Adds the function _stroke as a listener to the event pointermove notified by the canvas when the user presses a pointer in the canvas. Removes the function _stroke as a listener to the event pointermove when the user stops pressing in the canvas with a pointer and sets the last position of the drawing tool to 0.

  1.     w.addEventListener('touchstart', (e) => {
  2.         e.preventDefault();
  3.  
  4.         if (e.targetTouches.length === 1)
  5.             w.addEventListener('touchmove', _stroke, false);
  6.     }, false);
  7.  
  8.     w.addEventListener('touchend', (e) => {
  9.         e.preventDefault();
  10.  
  11.         w.removeEventListener('touchmove', _stroke, false), x0 = y0 = 0;
  12.     }, false);
  13.  
  14.     return this;
  15. }

Adds the function _stroke as a listener to the event touchmove notified by the canvas when the user touches the canvas with one finger. Removes the function _stroke as a listener to the event touchmove when the user stops touching the canvas and sets the last position of the drawing tool to 0.

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'; ?>

Defines the background color, the width and the height of the drawing area, the width and the color of the line, the color of the trash can.

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

Defines the identifier of the <div> which surrounds the test display.

  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. }

Configures the look of the drawing area. Puts the trash can at the bottom right.

  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="fa fa-trash"></i>
  5. </div>
  6. </div>

Creates the <div> of the test display with a canvas and the image of a button.

  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'); ?>

Includes the code of all the necessary classes.

  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'));

Creates an instance of Signature and configures its widget, the canvas.

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

Erases the signature if the trash can is clicked.

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

Erases the signature if the Del key is pressed in the canvas.

  1. const storage = sessionStorage;

Accesses the storage space of the 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. }

If a data URL is saved in the storage space, displays the image it contains in the canvas.

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

Saves the image drawn in the canvas in the storage space as a data URL when the pointer leaves the drawing area.

SEE ALSO

View, Drawingarea, Validator

Comments

Your comment:
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip help 2000

Enter a maximum of 2000 characters.
Improve the presentation of your text with the following formatting tags:
[p]paragraph[/p], [b]bold[/b], [i]italics[/i], [u]underline[/u], [s]strike[/s], [quote]citation[/quote], [pre]as is[/pre], [br]line break,
[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]command[/code], [code=language]source code in c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].