SignatureDirective in Ionic Using szimek/signature_pad

Hi ,I have Written a SignaturePad directive using Signature_Pad in Ionic Framework.
Please Follow and use the code to create the directive

1.Download the signature_pad js from here and add it into your js folder
2.Add this js file path in index.html file

<script src="lib/ionic/js/signature_pad.js"></script> 

3.Create Directive

MyController.directive('signaturepad', [
    '$ionicModal'
    function($ionicModal) {
        var canvasPad, signaturePad;
        return {
            /* Only use as <SignaturePad> tag */
            restrict: 'E',

            /* Our template */
            templateUrl: 'templates/sign_pad.html',

            link: function(scope, element, attrs) {

                scope.parentsignature = attrs.parentsignature || ' ';

                $ionicModal.fromTemplateUrl('templates/signature.html', {
                    scope: scope,
                    animation: 'slide-in-up'
                }).then(function(modal) {
                    scope.modal = modal;

                });

                scope.openSignPad = function() {
                 
                    scope.modal.show();
                    canvasPad = document.getElementById("signature-pad");
                    scope.resizeCanvas(); // To re size the canvas according to the mobile devices
                    signaturePad = new SignaturePad(canvasPad);
                    signaturePad.minWidth = 1;
                    signaturePad.maxWidth = 1.5;
                    signaturePad.dotSize = 3;
                    signaturePad.penColor = "rgb(66, 133, 244)";

                };
                scope.closeModal = function() {
                    scope.modal.hide();
                };
                //Cleanup the modal when we're done with it!
                scope.$on('$destroy', function() {
                    scope.modal.remove();
                });
                // Execute action on hide modal
                scope.$on('modal.hidden', function() {
                    // Execute action
                });
                // Execute action on remove modal
                scope.$on('modal.removed', function() {
                    // Execute action
                });

                scope.savePSign = function() {
                    if (signaturePad.isEmpty()) {
                        utilService.showWarning("Please Sign !");
                    } else {

                        scope.parentsignature = signaturePad.toDataURL();             
                        scope.closeModal();
                        
                    }
                };
                scope.clearPSign = function() {
                    signaturePad.clear();
                };
                scope.resizeCanvas= function() {
                    var ratio = window.devicePixelRatio || 1;
                    canvasPad.width = canvasPad.offsetWidth * ratio;
                    canvasPad.height = canvasPad.offsetHeight * ratio;
                    canvasPad.getContext("2d").scale(ratio, ratio);
                };

            }
        }
    }
]);

4. Create sign_pad.html and add the below code

    <img height="60" width="300" ng-src="{{parentsignature}}" ng-click="openSignPad()"> 

5.Create signature.html and the below code

 <ion-modal-view> 

    <div  class="m-signature-pad">
    <div class="m-signature-pad--body">
      <canvas id="signature-pad"></canvas>
	  
    </div>
 
      <div class="description" >Sign above</div>
      <button class="button clear" data-action="clear" ng-click="clearPSign()">Clear</button>
      <button class="button save" data-action="save" ng-click="savePSign()">Save</button>
    </div>	 
</div>		
 </ion-modal-view>

6. Add the element in require html form

    <signaturepad> </signaturepad>

6 Likes

Hello, I tried using your code but i have a hard time with the scaling on my samsung phone. (android 4.1.2). It looks like everything is scales X2 when drawing on the screen. The signature area seems transparent with only the grey backdrop visible… Do you have a white surface because of your CSS ?

Also, the image does not appear when save is pressed. on the desktop in chrome browser, the base-64 encoded image src give the error: net::ERR_UNKNOWN_URL_SCHEME, because it gets an “unsafe” in the url of the image in wign_pad.html: src="unsafe:data:image/png;base64… " instead of src="data:image/png;base64 … "

EDIT: Nevermind, Fixed that part by adding this to my .config:

.config(function($stateProvider, $urlRouterProvider, $compileProvider) {

  $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|file|blob|content):|data:image\//);

Now I only need to fix the fact that the drawing is scled up and displaced in relation to where I actualy draw on the screen!

Please give me some tips to use your signature directive! (or a working example on jsfiddle or codepen or even a single page app )

Anyways i am very grateful for what you did so far!
Thank you!

@boltex Could you share some screen shot .

I have fixed the scaling problem by forcing the ratio at 1.0 :
var ratio = 1.0;

instead of window.devicePixelRatio.

Now my only problem is having a better framerate to capture a more fluid and natural signature appearance.
I’m doing tests by having everything right in the screen, no modals, no shadows, no ion-view. etc…

I’ll report here later today or this week-end. Thanks again for your help or suggestions! :slight_smile:

1 Like

This is fantastic, however I’m trying to use it with more than one signature and I cant figure out why the second signature doesnt register any thing. it doesnt error, just wont accept anything in the canvasPad.

Any Ideas?
thanks

I had the same question, and here is my code, hope it helps you.

Directive

.directive('signature', function ($ionicModal) {
    var canvas = null,
      ratio = 1.0;

    return {
      scope: {
        signature: '=ngModel'
      },
      link: function ($scope, $element, $attrs, $controller) {
        $scope.signature = null;
        $scope.signaturePadModel = {};

        $ionicModal.fromTemplateUrl('components/signature/signaturePad.html', {
          animation: 'slide-in-up',
          scope: $scope,
        }).then(function(modal) {
          $scope.signatureModal = modal;
        });

        $scope.$on('$destroy', function () {
          $scope.signatureModal.remove();
        });

        $scope.openSignatureModal = function () {
          $scope.signatureModal.show();
          canvas = angular.element($scope.signatureModal.modalEl).find('canvas')[0];

          $scope.signaturePad = new SignaturePad(canvas, {
            backgroundColor: '#FFF',
            minWidth: 1,
            maxWidth: 1.5,
            dotSize: 3,
            penColor: 'rgb(66, 133, 244)',
            onEnd: function () {
              $scope.signature = $scope.signaturePad.toDataURL();
            }
          });

          if ($scope.signature) {
            $scope.signaturePad.fromDataURL($scope.signature);
          }
          $scope.resizeCanvas();
        };

        $scope.resizeCanvas = function () {
          canvas.width = canvas.offsetWidth * ratio;
          canvas.height = canvas.offsetHeight * ratio;
          canvas.getContext('2d').scale(ratio, ratio);          
        };

        $scope.clear = function () {
          $scope.signaturePadModel.signatureConfirm = false;
          $scope.signaturePad.clear();
          $scope.signature = null;
        };

        $scope.save = function () {
          $scope.signaturePadModel = {};
          $scope.signatureModal.hide();
        };
      },
      require: 'ngModel',
      replace: true,
      restrict: 'A',
      templateUrl: 'components/signature/signatureButton.html'
    };
  });

Button template

<div>
  <a ng-hide="signature" class="button button-clear button-positive button-small" ng-click="openSignatureModal()">Tap to sign</a>
  <div ng-show="signature">
    <p><a class="button button-clear button-positive button-small" ng-click="openSignatureModal()">Edit Signature</a></p>
    <img ng-src="{{signature}}" style="width:100%;" />
  </div>
</div>

Modal Template

<ion-modal-view>
  <ion-header-bar class="bar-positive">
    <h1 class="title">Add Signature</h1>
  </ion-header-bar>
  <ion-content scroll="false">
    <div class="card list">
      <div class="item item-body">Please use your finger or stylus to sign below</div>
      <canvas id="signature-canvas" class="padding-horizontal item" style="width: 100%;"></canvas>
    </div>
    <div class="button-bar padding">
      <button class="button" ng-click="clear(); signatureModal.hide()">Cancel</button>
      <button class="button" ng-click="clear()">Clear</button>
      <button class="button button-positive" ng-disabled="!signature" ng-click="save()">Accept</button>
    </div>
  </ion-content>
</ion-modal-view>

Usage

<input signature ng-model="signatureOne"></input>
<input signature ng-model="signatureTwo"></input>

Note that im binding an ng-model to the directive in which will store the signature data, so you can have as many as you want using different ng-model attributes.

Hope it helps.
Cheers

2 Likes

Awesome! I’ll dig into it thanks for the reply.

Really awesome, thank you!!

I’ve put this code in this repo and refactored the name and things, still no bower and sugar but will come soon.
Hope it helps

1 Like

Looks good - has anyone persisted this and used it successfully? I am saving it to a mongo database by using canvas.toDataURL('image/png) and then saving. When I load the image, the background is black. Is there a quick/easy/common way to set the background color?

I would have expected it to be transparent by default, but then it should match the app? (white).

I don’t think storing the b64 in a DB is a good idea, besides that you can config the signature plugin to make transparent imgs (white bg or other stuff), what i just did it’s a simple port from what’s in this post. Im planning to make a full customizable directive tough.

Check my previous comment, there’s a config in which you set the background color, and is set to white:

$scope.signaturePad = new SignaturePad(canvas, {
            backgroundColor: '#FFF',
            minWidth: 1,
            maxWidth: 1.5,
            dotSize: 3,
            penColor: 'rgb(66, 133, 244)',
            onEnd: function () {
              $scope.signature = $scope.signaturePad.toDataURL();
            }
          });

Please share your code so we can help you.

Hi

I am founding some issue with this. it’s like when i am drawing my signature it points to different location than my touch.

can you please tell me about this ?

force the ratio to be 1.0

$scope.resizeCanvas = function () {
var ratio = 1.0;
          canvas.width = canvas.offsetWidth * ratio;
          canvas.height = canvas.offsetHeight * ratio;
          canvas.getContext('2d').scale(ratio, ratio);          
        };
2 Likes

This works when width is declared, but if you declared the height this doesn’t work, in this case the ratio which should be ?

Hello.
Is it possible to save background image with a drawing ?

Hi very helpful…but i’m very rookie, there is some sample code app in github to download? because your code will be perfect as starter.
Thank you again.

I tried to change the size of the canvas since it was always 300x150, but it had an zoom effect on it and when I try to draw on it, the line is misplaced, as if the coordenates are being translated and scaled to the bigger size of the canvas from the drawing point I start.

I’m showing the canvas on modal as in the example:

<ion-modal-view>

  <div  class="m-signature-pad">
    <div class="m-signature-pad--body">
      <canvas id="signature-pad"></canvas>
    </div>
  </div>
</ion-modal-view>

I tried to set the style for the canvas to 100% so it would fill all of the width and wanted to set the height at 400px, but the result looked like this:

The code on my controller is the same as in the example:

   var canvasPad, signaturePad;
    $ionicModal.fromTemplateUrl('templates/signature_form.html', {
      scope: $scope,
      animation: 'slide-in-up'
    }).then(function(modal) {
      $scope.modal = modal;

    });

    $scope.openSignatureModal = function(){
      $scope.modal.show();
      canvasPad = document.getElementById("signature-pad");
      $scope.resizeCanvas(); 
      signaturePad = new SignaturePad(canvasPad);
      signaturePad.minWidth = 1;
      signaturePad.maxWidth = 1.5;
      signaturePad.dotSize = 3;
      signaturePad.penColor = "rgb(66, 133, 244)";
    }

    $scope.closeModal = function() {
      $scope.modal.hide();
    };

    $scope.saveSignature = function() {
      if (signaturePad.isEmpty()) {
        utilService.showWarning("Please Sign !");
      } else {

        $scope.parentsignature = signaturePad.toDataURL();
        $scope.closeModal();

      }
    };
    $scope.clearSignature = function() {
      signaturePad.clear();
    };
    $scope.resizeCanvas= function() {
      var ratio = window.devicePixelRatio || 1;
      canvasPad.width = canvasPad.offsetWidth * ratio;
      canvasPad.height = canvasPad.offsetHeight * ratio;
      canvasPad.getContext("2d").scale(ratio, ratio);
    };

How can I solve this issue? Am I doing something wrong or am I missing something? It’s weird for me to try to change the canvas size and the drawing point to be scaled and translated.

So I just found the reason why the image looks like that, I was trying out different sizes on the developer’s console on Chrome, that’s the reason behind the weird behavior, once I set my styles on my sheet, the canvas was rendered at the proper size for my project and was able to draw on it.

The problem now seems to be my inability to save the image with a white background, I tried setting the background-color: white !important on my CSS but when I loaded the image it appeared with a transparent background:

I could just render the image on a div with a white background, but the requirement needs for a signature with a white background.

The documentation for the library states that the property backgroundColor can be set to any non-trasnparent color, but only for JPEG images, I tried this for a PNG image and it got saved with a transparent background.

Does anyone know how to solve this?

EDIT

I checked the Draw over image example from the author’s page and the way he instantiated the SignaturePad gave away a solution for this issue:

var signaturePad = new SignaturePad(document.getElementById('signature-pad'), {
  backgroundColor: 'rgba(255, 255, 255, 0)',
  penColor: 'rgb(0, 0, 0)'
});

If you set the background color like this, instead of doing signaturePad.backgroundColor = 'rgba(255,255,255,1)', then the background color takes effect and when you save the image and you display it later it will be shown with a background color.

Did you try to use zoom in this plugin ? Is it possible ?

There would be an example in Ionic 2 ?