/** * Created by rburson on 3/18/16. */ /** * Smoothing techniques. * http://perfectionkills.com/exploring-canvas-drawing-techniques/ */ import * as React from 'react' import { CvState, CvProps, CvValueAdapter, CvValueListener, ColorUtil, ImageUtil, CvImagePackageUrl } from 'catreact' import { Log, Color, SignatureCapture } from 'catavolt-sdk' interface SigBundle { listener:CvValueListener, colors:{background:Color, line:Color }, size: {width:number, height:number}, ratio:{width:number, height:number} } /** * Value to be assigned when CvSignaturePopup is mounted. */ let openSignaturePopupListener:CvValueListener; export function openSignaturePopup(listener:CvValueListener, signature?:SignatureCapture, ratio?:{width:number, height:number}):void { if (openSignaturePopupListener != null) { // This is the mechanism that gets us inside the component's instance if (signature) { let c = { background: signature.backgroundColor, line: signature.lineColor } let s = {width:signature.captureBounds.width.value, height:signature.captureBounds.height.value} openSignaturePopupListener({listener: listener, colors: c, size:s, ratio:ratio}); } else { // Provide some defaults let c = { background: new Color(null, 255,255,255,1), line: new Color(null, 0,0,0,1) } let s = { width: 800, height: 600 } let r = { width: 400, height: 200 } openSignaturePopupListener({listener: listener, colors: c, size:s, ratio:r}); } } } export interface CvSignaturePopupState extends CvState { resultListener:CvValueListener, canvas?:HTMLCanvasElement, lineColor?:Color, backgroundColor?:Color, width?:number, height?:number, drawingStatus:{isDrawing:boolean, someDrawn:boolean} } export interface CvSignaturePopupProps extends CvProps { } /** Component that overlays a signature popup. */ export const CvSignaturePopup = React.createClass({ componentWillMount: function() { let signatureProvider = new CvValueAdapter(); signatureProvider.subscribe(this._handleParamChange); openSignaturePopupListener = signatureProvider.createValueListener(); window.addEventListener("mouseup", this._onMouseUp); }, componentWillUnmount() { window.removeEventListener("mouseup", this._onMouseUp); this.state.canvas = null; }, getDefaultProps: function () { return {paramProvider:null} }, getInitialState: function() { return { resultListener: null, forceRedraw: 1, drawingStatus: {isDrawing: false, someDrawn: false } }; }, render: function () { return (
{ let visible:boolean = (this.state != null) && (this.state.resultListener != null); if(visible) { let m:any = $(d); if(m && m.modal){ m.modal({show:true, keyboard: false, backdrop: 'static'} ) } let ctx:CanvasRenderingContext2D = this._get2dContext(); ctx.strokeStyle = ColorUtil.toColor(this.state.lineColor); ctx.lineWidth = 7; ctx.lineCap = "round"; ctx.lineJoin = "round"; this._resetDrawing(); } else { let m:any = $(d); if(m && m.modal){ m.modal('hide') } } }}>

Signature Capture

{ this.state.canvas = c }} className="cv-signature-canvas" height={this.state.height} width={this.state.width} onMouseDown={this._onMouseDown} onMouseMove={this._onMouseMove}/>
); }, _get2dContext: function() { // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D return this.state.canvas.getContext("2d"); }, _getMousePos: function(event) { let rect = this.state.canvas.getBoundingClientRect(); return { x: event.clientX - rect.left, y: event.clientY - rect.top } }, _handleParamChange: function(sigBundle:SigBundle) { // resultListener:CvValueListener) { if (sigBundle.listener) { let maxW:number = Math.min(sigBundle.size.width, $(window).innerWidth() - 50); let maxH:number = Math.min(sigBundle.size.height, $(window).innerHeight() - 200); let size:any = ImageUtil.calculateAspectRatioFit(sigBundle.ratio.width, sigBundle.ratio.height, maxW, maxH); this.setState({backgroundColor: sigBundle.colors.background, lineColor: sigBundle.colors.line, width: size.width, height: size.height}); } this.setState({resultListener: sigBundle.listener}); }, _onMouseDown: function(event:MouseEvent) { if (this.state.canvas) { Log.debug("CvSignaturePopup:MouseDown"); let ctx: CanvasRenderingContext2D = this._get2dContext(); ctx.beginPath(); this.state.drawingStatus.isDrawing = true; this.state.drawingStatus.someDrawn = false; let pos = this._getMousePos(event); ctx.moveTo(pos.x, pos.y); } }, _onMouseUp: function(event:MouseEvent) { if (this.state.drawingStatus.isDrawing) { Log.debug("CvSignaturePopup:MouseUp"); let ctx:CanvasRenderingContext2D = this._get2dContext(); let pos = this._getMousePos(event); if (!this.state.drawingStatus.someDrawn) { // If just a mouse click, draw a dot. ctx.strokeStyle = ColorUtil.toColor(this.state.lineColor); ctx.lineTo(pos.x +1, pos.y +1); ctx.stroke(); } ctx.closePath(); this.state.drawingStatus.isDrawing = false; this.state.drawingStatus.someDrawn = false; } }, _onMouseMove: function(event) { if (this.state.drawingStatus.isDrawing) { let pos = this._getMousePos(event); let ctx:CanvasRenderingContext2D = this._get2dContext(); ctx.strokeStyle = ColorUtil.toColor(this.state.lineColor); ctx.lineTo(pos.x, pos.y); ctx.stroke(); ctx.moveTo(pos.x, pos.y); this.state.drawingStatus.someDrawn = true; Log.debug("CvSignaturePopup:MouseMove x: " + pos.x + " y: " + pos.y); } }, _resetDrawing:function() { let ctx:CanvasRenderingContext2D = this._get2dContext(); ctx.fillStyle = ColorUtil.toColor(this.state.backgroundColor); ctx.fillRect(0,0,this.state.width, this.state.height); } });