Skip to content

Instantly share code, notes, and snippets.

@calebergh
Created February 23, 2020 18:59
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save calebergh/65b7f0f8b5d7e5d1e6cb977a4cb907f4 to your computer and use it in GitHub Desktop.
Save calebergh/65b7f0f8b5d7e5d1e6cb977a4cb907f4 to your computer and use it in GitHub Desktop.
Electronic Signature Pad for Angular 8
import { Directive, ElementRef, EventEmitter, HostListener, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
@Directive({
// tslint:disable-next-line:directive-selector
selector: '[signature]',
})
export class SignatureDirective implements OnInit, OnChanges {
@Output() imgSrc = new EventEmitter<string>();
@Input('clear') clearMe;
@Input('options') options;
private context;
private density: number;
private isDrawing = false;
private sigPadElement;
ngOnInit() {
this.sigPadElement = this.signaturePad.nativeElement;
this.context = this.sigPadElement.getContext('2d');
this.context.strokeStyle = this.options.color || '#3742fa';
this.context.lineWidth = this.options.width || 2;
if ( this.options.blur) {
this.context.shadowBlur = this.options.blur || 2;
this.context.shadowColor = this.options.blurColor || this.context.strokeStyle;
}
this.context.lineCap = 'round';
this.context.lineJoin = 'round';
this.density = window.devicePixelRatio || 1;
}
ngOnChanges(changes: SimpleChanges) {
if (!this.context) {
return;
}
if (changes.clearMe) {
this.clear();
this.save();
}
}
constructor(private signaturePad: ElementRef) {
}
@HostListener('touchstart', ['$event'])
handleTouchStart(e) {
e.preventDefault();
this.isDrawing = true;
this.start(e, 'layer');
}
@HostListener('touchmove', ['$event'])
handleTouchMove(e) {
if (!this.isDrawing) {
return;
}
e.preventDefault();
this.draw(e, 'layer');
}
@HostListener('document:touchend', ['$event'])
@HostListener('document:mouseup', ['$event'])
onMouseUp() {
if ( this.isDrawing) {
this.save();
}
this.isDrawing = false;
}
@HostListener('mousedown', ['$event'])
onMouseDown(e) {
this.isDrawing = true;
this.start(e);
}
@HostListener('mousemove', ['$event'])
onMouseMove(e) {
if (!this.isDrawing) {
return;
}
this.draw(e);
}
private start(e, type: 'client' | 'layer' = 'client') {
const coords = this.relativeCoords(e, type);
this.context.moveTo(coords.x, coords.y);
}
private draw(e, type: 'client' | 'layer' = 'client') {
const coords = this.relativeCoords(e, type);
this.context.lineTo(coords.x, coords.y);
this.context.stroke();
}
private relativeCoords(event, type: 'client' | 'layer') {
const bounds = this.sigPadElement.getBoundingClientRect();
let x = event[ type + 'X' ];
let y = event[ type + 'Y' ];
if ('layer' !== type) {
x -= bounds.left;
y -= bounds.top;
}
return { x, y };
}
clear() {
this.context.clearRect(0, 0, this.sigPadElement.width, this.sigPadElement.height);
this.context.beginPath();
}
save() {
this.imgSrc.emit(this.sigPadElement.toDataURL('image/png'));
}
}
@ahmedfarid-dev
Copy link

first of all ,thanks a lot for this great directive
I have only one problem ,when toggling device toolbar on google chrome ,to test the code in responsive and in different screens ,it doesn't draw and events in the directive are not fired ,any idea why is that ?

@calebergh
Copy link
Author

first of all ,thanks a lot for this great directive I have only one problem ,when toggling device toolbar on google chrome ,to test the code in responsive and in different screens ,it doesn't draw and events in the directive are not fired ,any idea why is that ?

The directive does not watch for window resize events, but certainly could be made to do so. Adding a HostListener for document resize, and triggering some of the "init" code would likely make it work in a responsive manner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment