sandro.carrara Posted May 14, 2015 Posted May 14, 2015 hi, we need to develop a mobile web app that can acquire the signature of a customer. How can i do that? Some times ago there was a canvasmobiledemo but i can't find it anymore. thanks. regards.
Abaksoft Posted May 15, 2015 Posted May 15, 2015 My respect Alessandro Carrara, Why don't you use a login form ?
sandro.carrara Posted May 18, 2015 Author Posted May 18, 2015 I need something different. I have an agent that need to acquire the signature of a client to confirm a specific order.
Ron Posted May 19, 2015 Posted May 19, 2015 I assume you can use the canvas, just get the right screen size set up, log the mouse movements when mouse is down, draw the pixels on the canvas, and upload the canvas data by ajax to the server afterwards....process it and save as image, and load it back to the client again as confirmation. Write the client part in javascript, use a htmlframe with a <canvas id="mycanvas"> and write the mouse handlers in JS too, and then use an ajaxcall to the htmlframe, picking up that in ajaxevent, when uploading the canvas data. Load the JS into the htmlframe on formshow e.g. This works very well, and is the only good solution when needing to capture mouse movements, as far as I know.
Ron Posted May 19, 2015 Posted May 19, 2015 //example JS code for capturing mouse events, load this into htmlfram //turn screenmask off by UniSession.AddJS('myMask.hide();'); after saving canvas data <canvas id="mycanvas"> <script type="text/javascript"> var canvas = document.getElementById("mycanvas"); var ctx = canvas.getContext("2d"); var mDown = false; var myMask = new Ext.LoadMask(MainForm.myHTMLFrame, {msg:"Saving data ..."}); function drawStuff() { //do your canvas drawing here... ctx.moveTo(...) } function relMouseCoords(event){ var totalOffsetX = 0; var totalOffsetY = 0; var canvasX = 0; var canvasY = 0; var currentElement = this; do{ totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft; totalOffsetY += currentElement.offsetTop - currentElement.scrollTop; } while(currentElement = currentElement.offsetParent); canvasX = event.pageX - totalOffsetX; canvasY = event.pageY - totalOffsetY; return {x:canvasX, y:canvasY} } HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords; $("#mycanvas").mousemove(function(event){ //store mouse movements if(mDown){ coords = canvas.relMouseCoords(event); push(myArray, {x: coords.x, y: coords.y}); drawStuff(); } }); $("#mycanvas").mousedown(function(event){ //skip right mouse up if(event.which===3) return; //start logging mDown = true; }); $("#mycanvas").mouseup(function(event){ //skip right mouse up if(event.which===3) return; //turn screenmask on... myMask.show(); ajaxRequest(MainForm.myHTMLFrame, ['saveCanvasData'], { myArray... }); }); window.addEventListener('resize', updateCanvas, true); function updateCanvas() { canvas.width = MainForm.myHTMLFrame.getWidth(); canvas.height = MainForm.myHTMLFrame.getHeight(); drawStuff(); } updateCanvas(); </script>
sandro.carrara Posted May 20, 2015 Author Posted May 20, 2015 thank you very much for the suggestion, but i don't know JS at all. I have no idea of what to write in drawStuff(). If you have already written a working sample project, would you be so kind to share it here in the forum? thanks a lot.
Ron Posted May 22, 2015 Posted May 22, 2015 Hi Sandro; The basic idea is that as the mouse moves, it reports x and y coordinates, and you push these into an array. THen in drawStuff() you simply draw these pixels, by drawing lines between them, as you loop through the array, something like this: ctx.beginPath(); ctx.strokeStyle = "#000000"; //black color ctx.lineWidth = 0.8; ctx.lineCap = 'square'; for(i=0;i<myArray.length-1;i++){ ctx.moveTo(myArray.x, myArray.y); ctx.lineTo(myArray[i+1].x, myArray[i+1].y); } ctx.stroke(); ctx.closePath(); Basic Javscript is not difficult at all, and you will get used to the syntax in no time, and W3Schools have all the info you need. My impression is that Javascript is a very powerful language, I simply love it ! It is amazing what you can do, and with a knowledge of JS combined with Unigui, you can create almost anything.. Best to just dive into it ! And the communication between JS in the client and Unigui, is so simple and easy to set up, it is like a walk in the park compared to creating things piece by piece in PHP for instance, and also much easier than Node & various JS frameworks like backbone.JS, sails.JS etc, even though you have JS on both sides there. Tip: Use docpad, with LiveReload, when you make JS code. I do that, and when I click Ctrl-S, the browser is updated in the background, and with the console you get easy debugging. This way it is so FAST to develop client code with JS, it is fun and you learn JS fast too, because of this close feedback loop. Anyway, after the signature is ok, you just upload this to the server, meaning that array, and save it, and reconstruct the signature image based on that pixel data.
Ron Posted May 22, 2015 Posted May 22, 2015 Here is an example of JS code which works in docpad, as signature.js: $(document).ready( function() { //canvas id="mycanvas"> //<script type="text/javascript"> var canvas = document.getElementById("mycanvas"); var ctx = canvas.getContext("2d"); var mDown = false; var myArray = []; var coords = []; function drawStuff() { //do your canvas drawing here... ctx.beginPath(); ctx.fillStyle = "#EEEEEE"; ctx.rect(0,0,canvas.width, canvas.height); ctx.fill(); ctx.beginPath(); ctx.strokeStyle = "#000000"; //black color ctx.lineWidth = 0.8; ctx.lineCap = 'square'; var i = 0; for(i=0;i<(myArray.length-1);i++){ ctx.moveTo(myArray[i].x, myArray[i].y); ctx.lineTo(myArray[i+1].x, myArray[i+1].y); } ctx.stroke(); ctx.closePath(); } function relMouseCoords(event){ var totalOffsetX = 0; var totalOffsetY = 0; var canvasX = 0; var canvasY = 0; var currentElement = this; do{ totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft; totalOffsetY += currentElement.offsetTop - currentElement.scrollTop; } while(currentElement = currentElement.offsetParent); canvasX = event.pageX - totalOffsetX; canvasY = event.pageY - totalOffsetY; return {x:canvasX, y:canvasY} } HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords; $("#mycanvas").mousemove(function(event){ //store mouse movements if(mDown){ coords = canvas.relMouseCoords(event); myArray.push({x: coords.x, y : coords.y}); drawStuff(); } }); $("#mycanvas").mousedown(function(event){ //skip right mouse up if(event.which===3) return; //start logging mDown = true; drawStuff(); }); $("#mycanvas").mouseup(function(event){ //skip right mouse up if(event.which===3) return; mDown = false; //turn screenmask on... //myMask.show(); //ajaxRequest(MainForm.myHTMLFrame, ['saveCanvasData'], { myArray... }); }); window.addEventListener('resize', updateCanvas, true); function updateCanvas() { //canvas.width = MainForm.myHTMLFrame.getWidth(); //canvas.height = MainForm.myHTMLFrame.getHeight(); drawStuff(); } updateCanvas(); //</script> }); In addition to this, you have this index.html: --- title: "Welcome!" layout: "default" isPage: true --- <canvas id="mycanvas" style="border:0px solid #990000;"> </canvas> And this eco layout file: <html> <head> <title><%= @document.title %> | My Website</title> <%- @getBlock("meta").toHTML() %> </head> <body> <%- @content %> <%- @getBlock("scripts").add(["/vendor/jquery.js","/scripts/signature.js",]).toHTML() %> </body> </html> Notice that jQuery is there too. Of course you have to modify this code, to split the paths you draw, so not all pixels are connected, and then create the upload code. If you want me to do it for you, we can maybe work out a deal, but this should not be too hard to finish.
Ron Posted May 22, 2015 Posted May 22, 2015 I experimented a little with the drawing routine, and came up with a simple solution where you push invalid pixel data to split the paths: function drawStuff() { //first clear the canvas and draw a thin border ctx.beginPath(); ctx.strokeStyle = "#000000"; //black color ctx.lineCap = 'square'; ctx.lineWidth = 0.5; ctx.fillStyle = "#FFFFFF"; ctx.rect(0,0,canvas.width, canvas.height); ctx.fill(); ctx.stroke(); ctx.closePath(); //loop through the pixel data ctx.beginPath(); for(var i=0;i<(myArray.length-1);i++){ //when we encounter illegal pixel data, close the path if(myArray[i].x === -1){ ctx.stroke(); ctx.closePath(); ctx.beginPath(); } else //skip to valid pixel data and draw paths if(myArray[i+1].x != -1) { ctx.moveTo(myArray[i].x, myArray[i].y); ctx.lineTo(myArray[i+1].x, myArray[i+1].y); } } //close last path ctx.stroke(); ctx.closePath(); } And you do this in the mouseup event: $("#mycanvas").mouseup(function(event){ //skip right mouse up if(event.which===3) return; mDown = false; document.getElementById("mycanvas").style.cursor = 'default'; //push invalid pixel data to mark end of path myArray.push({x: -1, y : -1}); drawStuff(); //turn screenmask on... //myMask.show(); //ajaxRequest(MainForm.myHTMLFrame, ['saveCanvasData'], { myArray... }); }); In addition I have added a line to the mousedown event, changing cursor style: $("#mycanvas").mousedown(function(event){ //skip right mouse up if(event.which===3) return; //start logging mDown = true; document.getElementById("mycanvas").style.cursor = 'pointer'; drawStuff(); }); Testing this quickly, it seems to work. Of course this must be debugged re events and statuses etc. As the mouse leaves the canvas, the mouseup event will not be triggered, so you have to add a mouseout event - I guess - and set mDown=false to avoid a mouse "hang-up"...etc. - like this: $("#mycanvas").mouseout(function(event){ if(event.which===3) return; mDown = false; myArray.push({x: -1, y : -1}); document.getElementById("mycanvas").style.cursor = 'default'; drawStuff(); }); One can use this to create a simple CAPTCHA routine, where e.g. the user must draw a line between two shapes, to continue. 1
sandro.carrara Posted May 25, 2015 Author Posted May 25, 2015 Thank you very much. I really appreciate your help. i'm trying to make things work with javasccript but i've problems when i put js code in unimHTMLFrame. I don't know if it's the same issue reported here: http://forums.unigui.com/index.php?/topic/4997-mobile-script-in-unimhtmlframe/?p=25472
Ron Posted June 17, 2015 Posted June 17, 2015 Hi, That should be no problem. But make sure you got this: <script type="text/javascript"> <----------------- And not only <script> as the link you mentioned.
Bocchi Posted March 16, 2017 Posted March 16, 2017 Anyone can tell me how to use this code in a unigui mobile app? Thanks.
Recommended Posts