So here is simple application with complete source that captures a signature and then lets you save it on the server. The client side programming is done with the help of HTML5 canvas, ExtJs 4 JavaScript framework. On the server side its Java Servlet. You can replace them with any technology of your linking such as plain JavaScript or jQuery and php for server programming. You can also use this as a starting point for your own paint application.
Please Note: I used the computer mouse to draw that Text on my browser but if you use the finger on your touch screen the text will be much more smooth.
The application runs on any browser that supports the CANVAS element introduced in the HTML5. Also you can run the application on your iPad, iPhone, Android OS based smart phones and tablets. It should run on Windows and Blackberry smart phones and tablets as the application is not OS dependent. The backbone of this application is the HTML5 canvas element and the following events ...
- Browser Mouse events
- mousedown
- Fires when the user depresses the mouse button
- mousemove
- Fires when the user moves the mouse.
- mouseup
- Fires when the user releases the mouse button.
- Browser Touch events
- touchstart
- Happens every time a finger is placed on the screen
- touchmove
- Happens as a finger already placed on the screen is moved across the screen
- touchend
- Happens every time a finger is removed from the screen
Step 1: Create the HTML file - index.html
<!DOCTYPE html> <html> <head> <title>Signature Capture Example using HTML5 canvas</title> <link rel="stylesheet" type="text/css" href="extjs/resources/css/ext-all.css"> <script type="text/javascript" src="extjs/ext-all-debug.js"></script> <script type="text/javascript" src="app.js"></script> </head> <body> </body> </html>
Step 2: Create the ExtJs application JavaScript file - app.js
This has two buttons, one for saving the signature and the other one just to clear the signature in case you messed up. In addition to that we have the signature capture panel.Ext.Loader.setConfig({ enabled: true }); Ext.application({ name: 'MyApp', appFolder: 'app', controllers: [ 'Signature' ], launch: function() { Ext.create('Ext.container.Viewport', { margin: 10, defaults: { margin: 10, }, items: [{ xtype: 'label', html: '<b>Capture signature using using HTML5 canvas</b>' }, { xtype: 'signatureCapture', }, { xtype: 'button', text: 'Save Signature', id: 'save', disabled: true, }, { xtype: 'button', text: 'Clear Signature', id: 'clear' }] }); } });
Step 3: Signature Capture Panel - SignatureCapture.js
SignatureCapture panel has one child panel that contains the canvas element that we need to draw our signature.Ext.define('MyApp.view.SignatureCapture', { extend: 'Ext.Container', alias : 'widget.signatureCapture', layout: { type: 'vbox', align: 'stretch' }, width: 600, height: 300, border: 1, style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px'}, items: [ { xtype: 'panel', id: 'signature', html: '<canvas id="signaturePanel" width="600" height="300">no canvas support</canvas>' }] });
Step 4: Application controller file - Signature.js
This is the heart of the application where we get a reference to our canvas element and its 2d context. It takes care of saving the signature on the server with the help of an AJAX request. The image is sent to the server as a Base64 encoded string. To learn more about HTML5 canvas click on the link below ...HTML5 canvas tutorial for beginners - getContext() toDataURL() toBlob()
Ext.define('MyApp.controller.Signature', { extend : 'Ext.app.Controller', //define the views views : ['SignatureCapture'], //define refs refs: [{ ref: 'mySignature', selector: 'panel[id="signature"]' }], init : function() { this.control({ 'signatureCapture' : { afterrender : this.onPanelRendered }, 'viewport button[id=clear]' : { click : this.onClearSignature } , 'viewport button[id=save]' : { click : this.onSaveSignature } }); }, onClearSignature: function(button) { console.log('Clear Signature button clicked!'); signPad.width = signPad.width; signPadContext.lineWidth = 3; saveButton.disable(); }, onSaveSignature: function() { console.log('Save Signature button clicked!'); //Returns the content of the current canvas as an image that you can //use as a source for another canvas or an HTML element var data = signPad.toDataURL(); var signatureData = data.replace(/^data:image\/(png|jpg);base64,/, ""); //create an AJAX request Ext.Ajax.request({ url : 'SaveSignature', method:'POST', params : { 'signatureData' : signatureData }, scope : this, //method to call when the request is successful success : this.onSaveSuccess, //method to call when the request is a failure failure : this.onSaveFailure }); }, onPanelRendered: function(panel) { console.log('Signature Panel rendered, get ready to Sign!'); var view = panel.up('viewport'); saveButton = view.down('button[id=save]'); //get the signature capture panel signPad = Ext.getDom("signaturePanel"); if (signPad && signPad.getContext) { signPadContext = signPad.getContext('2d'); } if (!signPad || !signPadContext) { alert('Error creating signature pad.'); return; } signPad.width = this.getMySignature().getWidth(); signPad.height = this.getMySignature().getHeight(); //Mouse events signPad.addEventListener('mousedown', this.eventSignPad, false); signPad.addEventListener('mousemove', this.eventSignPad, false); signPad.addEventListener('mouseup', this.eventSignPad, false); //Touch screen events signPad.addEventListener('touchstart', this.eventTouchPad, false); signPad.addEventListener('touchmove', this.eventTouchPad, false); signPad.addEventListener('touchend', this.eventTouchPad, false); sign = new this.signCap(); signPadContext.lineWidth = 3; }, signCap: function() { var sign = this; this.draw = false; this.start = false; this.mousedown = function(event) { signPadContext.beginPath(); signPadContext.arc(event._x, event._y,1,0*Math.PI,2*Math.PI); signPadContext.fill(); signPadContext.stroke(); signPadContext.moveTo(event._x, event._y); sign.draw = true; saveButton.enable(); }; this.mousemove = function(event) { if (sign.draw) { signPadContext.lineTo(event._x, event._y); signPadContext.stroke(); } }; this.mouseup = function(event) { if (sign.draw) { sign.mousemove(event); sign.draw = false; } }; this.touchstart = function(event) { signPadContext.beginPath(); signPadContext.arc(event._x, event._y,1,0*Math.PI,2*Math.PI); signPadContext.fill(); signPadContext.stroke(); signPadContext.moveTo(event._x, event._y); sign.start = true; saveButton.enable(); }; this.touchmove = function(event) { event.preventDefault(); if (sign.start) { signPadContext.lineTo(event._x, event._y); signPadContext.stroke(); } }; this.touchend = function(event) { if (sign.start) { sign.touchmove(event); sign.start = false; } }; }, eventSignPad: function(event) { if (event.offsetX || event.offsetX == 0) { event._x = event.offsetX; event._y = event.offsetY; } else if (event.layerX || event.layerX == 0) { event._x = event.layerX; event._y = event.layerY; } var func = sign[event.type]; if (func) { func(event); } }, eventTouchPad: function(event) { var mySign = Ext.get("signature"); //in the case of a mouse there can only be one point of click //but when using a touch screen you can touch at multiple places //at the same time. Here we are only concerned about the first //touch event. Next we get the canvas element's left and Top offsets //and deduct them from the current coordinates to get the position //relative to the canvas 0,0 (x,y) reference. event._x = event.targetTouches[0].pageX - mySign.getX(); event._y = event.targetTouches[0].pageY - mySign.getY(); var func = sign[event.type]; if (func) { func(event); } }, onSaveFailure : function(err) { //Alert the user about communication error Ext.MessageBox.alert('Error occured during saving the signature', 'Please try again!'); }, onSaveSuccess : function(response, opts) { //Received response from the server response = Ext.decode(response.responseText); Ext.MessageBox.alert('Save Successful', 'File name is: ' + response.fileName); }, });
Step 5: Java Servlet for server side programming - SaveSignature.java
The Java Servlet creates an unique file name using current date and time. It uses the Base64 decoder to create a PNG image file from the image string.package com.as400samplecode; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.text.DateFormat; import java.text.SimpleDateFormat; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.gson.JsonObject; public class SaveSignature extends HttpServlet { private static final long serialVersionUID = 1L; private static final String DESTINATION_DIR_PATH ="/signatureFolder"; private File destinationDir, filePath; public SaveSignature() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // nothing here } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //PrintWriter to send the JSON response back PrintWriter out = response.getWriter(); //set content type and header attributes response.setContentType("text/html"); response.setHeader("Cache-control", "no-cache, no-store"); response.setHeader("Pragma", "no-cache"); response.setHeader("Expires", "-1"); JsonObject myObj = new JsonObject(); String signatureData = request.getParameter("signatureData"); String realPath = getServletContext().getRealPath(DESTINATION_DIR_PATH); String fileName = "Signature_" + getTodaysDate() + "_" + getCurrentTime() + ".png"; destinationDir = new File(realPath); if(!destinationDir.isDirectory()) { myObj.addProperty("success", false); myObj.addProperty("message", "Signature destination folder not found!"); } else { filePath = new File(realPath, fileName); Base64.decodeToFile(signatureData, filePath.getPath()); myObj.addProperty("success", true); myObj.addProperty("fileName", fileName); } out.println(myObj.toString()); out.close(); } private String getTodaysDate() { DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); String todaysDate = dateFormat.format(System.currentTimeMillis()); return todaysDate; } private String getCurrentTime() { DateFormat dateFormat = new SimpleDateFormat("kkmmss"); String currentTime = dateFormat.format(System.currentTimeMillis()); return currentTime; } }
No comments:
Post a Comment
NO JUNK, Please try to keep this clean and related to the topic at hand.
Comments are for users to ask questions, collaborate or improve on existing.