diff --git a/src/signature_pad.ts b/src/signature_pad.ts index c7a01af0..e4fd17a7 100644 --- a/src/signature_pad.ts +++ b/src/signature_pad.ts @@ -36,6 +36,12 @@ export interface PointGroupOptions { maxWidth: number; penColor: string; velocityFilterWeight: number; + /** + * This is the globalCompositeOperation for the line. + * *default: 'source-over'* + * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation + */ + compositeOperation: GlobalCompositeOperation; } export interface Options extends Partial { @@ -56,6 +62,7 @@ export default class SignaturePad extends SignatureEventTarget { public penColor: string; public minDistance: number; public velocityFilterWeight: number; + public compositeOperation: GlobalCompositeOperation; public backgroundColor: string; public throttle: number; @@ -83,6 +90,7 @@ export default class SignaturePad extends SignatureEventTarget { this.dotSize = options.dotSize || 0; this.penColor = options.penColor || 'black'; this.backgroundColor = options.backgroundColor || 'rgba(0,0,0,0)'; + this.compositeOperation = options.compositeOperation || 'source-over'; this._strokeMoveUpdate = this.throttle ? throttle(SignaturePad.prototype._strokeUpdate, this.throttle) @@ -314,7 +322,7 @@ export default class SignaturePad extends SignatureEventTarget { } }; - private _getPointGroupOptions(group?: PointGroup) { + private _getPointGroupOptions(group?: PointGroup): PointGroupOptions { return { penColor: group && 'penColor' in group ? group.penColor : this.penColor, dotSize: group && 'dotSize' in group ? group.dotSize : this.dotSize, @@ -324,6 +332,10 @@ export default class SignaturePad extends SignatureEventTarget { group && 'velocityFilterWeight' in group ? group.velocityFilterWeight : this.velocityFilterWeight, + compositeOperation: + group && 'compositeOperation' in group + ? group.compositeOperation + : this.compositeOperation, }; } @@ -361,8 +373,8 @@ export default class SignaturePad extends SignatureEventTarget { (event as PointerEvent).pressure !== undefined ? (event as PointerEvent).pressure : (event as Touch).force !== undefined - ? (event as Touch).force - : 0; + ? (event as Touch).force + : 0; const point = this._createPoint(x, y, pressure); const lastPointGroup = this._data[this._data.length - 1]; @@ -432,6 +444,7 @@ export default class SignaturePad extends SignatureEventTarget { this._lastVelocity = 0; this._lastWidth = (options.minWidth + options.maxWidth) / 2; this._ctx.fillStyle = options.penColor; + this._ctx.globalCompositeOperation = options.compositeOperation; } private _createPoint(x: number, y: number, pressure: number): Point { diff --git a/tests/fixtures/face.ts b/tests/fixtures/face.ts index e3235d8b..bdc19b7b 100644 --- a/tests/fixtures/face.ts +++ b/tests/fixtures/face.ts @@ -7,6 +7,7 @@ export const face: PointGroup[] = [ minWidth: 0.5, maxWidth: 2.5, velocityFilterWeight: 0.7, + compositeOperation: 'source-over', points: [ { time: 1523730547109, @@ -22,6 +23,7 @@ export const face: PointGroup[] = [ minWidth: 0.5, maxWidth: 2.5, velocityFilterWeight: 0.7, + compositeOperation: 'source-over', points: [ { time: 1523730547775, @@ -37,6 +39,7 @@ export const face: PointGroup[] = [ minWidth: 0.5, maxWidth: 2.5, velocityFilterWeight: 0.7, + compositeOperation: 'source-over', points: [ { time: 1523730548448, diff --git a/tests/fixtures/square.ts b/tests/fixtures/square.ts index d35f4ef8..f91ce800 100644 --- a/tests/fixtures/square.ts +++ b/tests/fixtures/square.ts @@ -7,6 +7,7 @@ export const square: PointGroup[] = [ minWidth: 0.5, maxWidth: 2.5, velocityFilterWeight: 0.7, + compositeOperation: 'source-over', points: [ { time: 1637131731972, diff --git a/tests/signature_pad.test.ts b/tests/signature_pad.test.ts index 36c92c38..521046cb 100644 --- a/tests/signature_pad.test.ts +++ b/tests/signature_pad.test.ts @@ -53,6 +53,21 @@ describe('#clear', () => { expect(pad.isEmpty()).toBe(true); expect(pad.toData()).toEqual([]); }); + + it('clear should apply erase option to the canvas context', () => { + const pad = new SignaturePad(canvas); + + pad.fromData(face); + expect(pad.isEmpty()).toBe(false); + + pad.penColor = 'pink'; + pad.compositeOperation = 'destination-out'; + + pad.clear(); + + const context = canvas.getContext('2d') as CanvasRenderingContext2D; + expect(context.globalCompositeOperation).toBe('destination-out'); + }) }); describe('#isEmpty', () => {