Skip to content
This repository has been archived by the owner on Nov 18, 2019. It is now read-only.

Commit

Permalink
Merge pull request #36 from legalthings/bounding-box-interval
Browse files Browse the repository at this point in the history
Update the bounding box using an interval rather than a timeout
  • Loading branch information
Sarfaraaz committed Oct 19, 2016
2 parents 351267e + 481d7c0 commit 85fdaeb
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 57 deletions.
16 changes: 10 additions & 6 deletions README.md
@@ -1,13 +1,17 @@
# Angular signature
# Angular Signature

AngularJS directive for the [signature pad](https://github.com/szimek/signature_pad/) JavaScript library by szimek.

_In contrast to other AngularJS modules for szimek's signature pad, this library doesn't apply any styling. The
directive only places the canvas, not any buttons. You bind the signature pad js calls to the functions in scope of your
_In contrast to other AngularJS directives for szimek's signature pad, this directive does not apply any styling. The
directive only places the canvas and allows you to bind your app to the signature pad by binding the functions in the scope of your
controller. This means you can call them from your own (custom) buttons._

![sign animation](https://cloud.githubusercontent.com/assets/100821/11911005/77b3e2fe-a5de-11e5-9221-cfaafb737cd7.gif)

## Demo

An online demo of the directive can be found [here](https://rawgit.com/legalthings/angular-signature/master/demo/index.html).

## Installation

Install this module using bower
Expand All @@ -30,17 +34,17 @@ Add the module to your app
<button ng-click="signature = accept()">Sign</button>
```

### Bootstrap modal
### Bootstrap Modal

This plugin works well in a [Angular UI bootstrap Modal](https://angular-ui.github.io/bootstrap/#/modal).
This plugin works well in a [Angular UI Bootstrap Modal](https://angular-ui.github.io/bootstrap/#/modal).

```js
angular.module('app').controller('SignModalCtrl', [
'$scope', '$modalInstance'
function ($scope, $modalInstance) {
$scope.done = function () {
var signature = $scope.accept();

if (signature.isEmpty) {
$modalInstance.dismiss();
} else {
Expand Down
9 changes: 9 additions & 0 deletions demo/app.js
@@ -0,0 +1,9 @@
angular.module('app', ['signature']);

angular.module('app').controller('AppCtrl', function($scope) {
$scope.boundingBox = {
width: 700,
height: 300
};
});

85 changes: 85 additions & 0 deletions demo/index.html
@@ -0,0 +1,85 @@
<!DOCTYPE html>
<html lang="en" data-ng-app="app" ng-controller="AppCtrl">
<head>
<meta charset="utf-8"/>
<title>Angular Signature demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">

<script src="https://cdnjs.cloudflare.com/ajax/libs/signature_pad/1.5.3/signature_pad.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="../src/signature.js"></script>
<script src="app.js"></script>

<style>
html, body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}

.container {
border: 1px solid red;
padding: 10px 10px 40px 10px;
position: relative;
margin: 0 auto 0 auto;
height: 100%;
}

.container .signature {
border: 1px solid orange;
margin: 0 auto;
cursor: pointer;
}

.container .signature canvas {
border: 1px solid #999;
margin: 0 auto;
cursor: pointer;
}

.container .buttons {
position: absolute;
bottom: 10px;
left: 10px;
}

.container .sizes {
position: absolute;
bottom: 10px;
right: 10px;
}

.container .sizes input {
width: 4em;
text-align: center;
}

.result {
border: 1px solid blue;
margin: 30px auto 0 auto;
height: 220px;
width: 568px;
}
</style>
</head>
<body>
<div class="container" ng-style="{'max-width': boundingBox.width + 'px', 'max-height': boundingBox.height + 'px'}">
<signature-pad accept="accept" clear="clear" height="220" width="568" dataurl="dataurl"></signature-pad>

<div class="buttons">
<button ng-click="clear()">Clear</button>
<button ng-click="dataurl = signature.dataUrl" ng-disabled="!signature">Reset</button>
<button ng-click="signature = accept()">Sign</button>
</div>
<div class="sizes">
<input type="text" ng-model="boundingBox.width"> x <input type="text" ng-model="boundingBox.height">
</div>
</div>

<div class="result" ng-show="signature">
<img ng-src="{{ signature.dataUrl }}">
</div>
</body>
</html>

109 changes: 58 additions & 51 deletions src/signature.js
Expand Up @@ -5,19 +5,19 @@

angular.module('signature', []);

angular.module('signature').directive('signaturePad', ['$window', '$timeout',
function ($window, $timeout) {
angular.module('signature').directive('signaturePad', ['$interval', '$timeout', '$window',
function ($interval, $timeout, $window) {
'use strict';

var signaturePad, element, EMPTY_IMAGE = 'data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAA=';
return {
restrict: 'EA',
replace: true,
template: '<div class="signature" style="width: 100%; max-width:{{width}}px"><canvas ng-mouseup="onMouseup()" ng-mousedown="notifyDrawing({ drawing: true })"></canvas></div>',
template: '<div class="signature" style="width: 100%; max-width:{{width}}px; height: 100%; max-height:{{height}}px;"><canvas style="display: block; margin: 0 auto;" ng-mouseup="onMouseup()" ng-mousedown="notifyDrawing({ drawing: true })"></canvas></div>',
scope: {
accept: '=',
clear: '=',
dataurl: '=',
accept: '=?',
clear: '=?',
dataurl: '=?',
height: '@',
width: '@',
notifyDrawing: '&onDrawing',
Expand All @@ -26,16 +26,11 @@ angular.module('signature').directive('signaturePad', ['$window', '$timeout',
'$scope',
function ($scope) {
$scope.accept = function () {
var signature = {};

if (!$scope.signaturePad.isEmpty()) {
signature.isEmpty = false;
} else {
signature.dataUrl = EMPTY_IMAGE;
signature.isEmpty = true;
}

return signature;
return {
isEmpty: $scope.dataurl === EMPTY_IMAGE,
dataUrl: $scope.dataurl
};
};

$scope.onMouseup = function () {
Expand All @@ -50,75 +45,86 @@ angular.module('signature').directive('signaturePad', ['$window', '$timeout',
defer handling mouseup event until $scope.signaturePad handles
first the same event
*/
$timeout()
.then(function () {
var result = $scope.accept();
$scope.dataurl = result.isEmpty ? undefined : result.dataUrl;
});
$timeout().then(function () {
$scope.dataurl = $scope.signaturePad.isEmpty() ? EMPTY_IMAGE : $scope.signaturePad.toDataURL();
});
};

$scope.clear = function () {
$scope.signaturePad.clear();
$scope.dataurl = undefined;
$scope.dataurl = EMPTY_IMAGE;
};

$scope.$watch("dataurl", function (dataUrl) {
if (dataUrl) {
$scope.signaturePad.fromDataURL(dataUrl);
if (!dataUrl || $scope.signaturePad.toDataURL() === dataUrl) {
return;
}

$scope.setDataUrl(dataUrl);
});
}
],
link: function (scope, element, attrs) {
var canvas = element.find('canvas')[0];
var parent = canvas.parentElement;
var scale = 0;
var ctx = canvas.getContext('2d');

var width = parseInt(scope.width, 10);
var height = parseInt(scope.height, 10);
var aspectRatio = height / width;

canvas.width = width;
canvas.height = height;

//Resize to fix UI Bootstrap Modal Show problem
$timeout(function(){
canvas.width = attrs.width;
canvas.height = attrs.height;
}, 500);


scope.signaturePad = new SignaturePad(canvas);

if (scope.signature && !scope.signature.$isEmpty && scope.signature.dataUrl) {
scope.signaturePad.fromDataURL(scope.signature.dataUrl);
}
scope.setDataUrl = function(dataUrl) {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.scale(1, 1);

scope.signaturePad.clear();
scope.signaturePad.fromDataURL(dataUrl);

$timeout().then(function() {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.scale(1 / scale, 1 / scale);
});
};

var calculateScale = function() {
var scaleWidth = Math.min(parent.clientWidth / width, 1);
var scaleHeight = Math.min(parent.clientHeight / height, 1);

var newScale = Math.min(scaleWidth, scaleHeight);

var calculateScale = function () {
// calculate parent Width;
var parentWidth = parent.offsetWidth;
if (parentWidth < width) {
// Calculate aspect ratio
var newWidth = parentWidth;
var newHeight = newWidth * aspectRatio;
canvas.style.height = newHeight + "px";
canvas.style.width = newWidth + "px";

// Calculate scale
var scale = width / newWidth;
ctx.resetTransform();
ctx.scale(scale, scale);
if (newScale === scale) {
return;
}
}

var newWidth = width * newScale;
var newHeight = height * newScale;
canvas.style.height = Math.round(newHeight) + "px";
canvas.style.width = Math.round(newWidth) + "px";

scale = newScale;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.scale(1 / scale, 1 / scale);
};

var resizeIH = $interval(calculateScale, 200);
scope.$on('$destroy', function () {
$interval.stop(resizeIH);
resizeIH = null;
});

angular.element($window).bind('resize', calculateScale);
scope.$on('$destroy', function () {
angular.element($window).unbind('resize', calculateScale);
});

calculateScale();

element.on('touchstart', onTouchstart);

element.on('touchstart', onTouchstart);
element.on('touchend', onTouchend);

function onTouchstart() {
Expand All @@ -144,3 +150,4 @@ angular.module('signature').directive('signaturePad', ['$window', '$timeout',

// Backward compatibility
angular.module('ngSignaturePad', ['signature']);

0 comments on commit 85fdaeb

Please sign in to comment.