Question

I'm facing an odd issue with firefox for android and html5 canvas.

I have a form that allows the customer to sign. The form will work perfectly on say chrome (screenshot 1) but will scramble the moment the customer attempts to sign on Firefox for android.

the JS code for the signature pad is from http://www.zetakey.com/codesample-signature.php

The js code is as follows:

// JavaScript Document

function signatureCapture() {

    //Actual Code starts here

    var parent=document.getElementById("canvas");
    parent.childNodes[0].nodeValue = "";

    var canvasArea=document.createElement("canvas");
    canvasArea.setAttribute("id", "newSignature");
    parent.appendChild(canvasArea);

    var canvas = document.getElementById("newSignature");
    var context = canvas.getContext("2d");

    if (!context) {
        throw new Error("Failed to get canvas' 2d context");
    }

    screenwidth = screen.width;

    //if (screenwidth < 480){
    //  canvas.width = screenwidth - 8 ;
    //  canvas.height = (screenwidth * 0.63) ;
    //}
    //else {
        canvas.width = 460 ;
        canvas.height = 300 ;
    //}

    context.fillStyle = "#fff";
    context.strokeStyle = "#444";
    context.lineWidth = 1.2;
    context.lineCap = "round";

    context.fillRect(0, 0, canvas.width, canvas.height);

    context.fillStyle = "#3a87ad";
    context.strokeStyle = "#3a87ad";
    context.lineWidth = 1;
    context.moveTo((canvas.width*0.042),(canvas.height * 0.7));
    context.lineTo((canvas.width*0.958),(canvas.height * 0.7));
    context.stroke();

    context.fillStyle = "#fff";
    context.strokeStyle = "#444";


    var disableSave = true;
    var pixels = [];
    var cpixels = [];
    var xyLast = {};
    var xyAddLast = {};
    var calculate = false;

    //functions
    {
        function remove_event_listeners() {
            canvas.removeEventListener('mousemove', on_mousemove, false);
            canvas.removeEventListener('mouseup', on_mouseup, false);
            canvas.removeEventListener('touchmove', on_mousemove, false);
            canvas.removeEventListener('touchend', on_mouseup, false);

            document.body.removeEventListener('mouseup', on_mouseup, false);
            document.body.removeEventListener('touchend', on_mouseup, false);
        }

        function get_board_coords(e) {
            var x, y;

            if (e.changedTouches && e.changedTouches[0]) {
                var offsety = canvas.offsetTop || 0;
                var offsetx = canvas.offsetLeft || 0;

                x = e.changedTouches[0].pageX - offsetx;
                y = e.changedTouches[0].pageY - offsety;
            } else if (e.layerX || 0 == e.layerX) {
                x = e.layerX;
                y = e.layerY;
            } else if (e.offsetX || 0 == e.offsetX) {
                x = e.offsetX;
                y = e.offsetY;
            }

            return {
                x : x,
                y : y
            };
        };

        function on_mousedown(e) {
            e.preventDefault();
            e.stopPropagation();

            canvas.addEventListener('mousemove', on_mousemove, false);
            canvas.addEventListener('mouseup', on_mouseup, false);
            canvas.addEventListener('touchmove', on_mousemove, false);
            canvas.addEventListener('touchend', on_mouseup, false);

            document.body.addEventListener('mouseup', on_mouseup, false);
            document.body.addEventListener('touchend', on_mouseup, false);

            empty = false;
            var xy = get_board_coords(e);
            context.beginPath();
            pixels.push('moveStart');
            context.moveTo(xy.x, xy.y);
            pixels.push(xy.x, xy.y);
            xyLast = xy;
        };

        function on_mousemove(e, finish) {
            e.preventDefault();
            e.stopPropagation();

            var xy = get_board_coords(e);
            var xyAdd = {
                x : (xyLast.x + xy.x) / 2,
                y : (xyLast.y + xy.y) / 2
            };

            if (calculate) {
                var xLast = (xyAddLast.x + xyLast.x + xyAdd.x) / 3;
                var yLast = (xyAddLast.y + xyLast.y + xyAdd.y) / 3;
                pixels.push(xLast, yLast);
            } else {
                calculate = true;
            }

            context.quadraticCurveTo(xyLast.x, xyLast.y, xyAdd.x, xyAdd.y);
            pixels.push(xyAdd.x, xyAdd.y);
            context.stroke();
            context.beginPath();
            context.moveTo(xyAdd.x, xyAdd.y);
            xyAddLast = xyAdd;
            xyLast = xy;

        };

        function on_mouseup(e) {
            remove_event_listeners();
            disableSave = false;
            context.stroke();
            pixels.push('e');
            calculate = false;
        };

    }//end

    canvas.addEventListener('mousedown', on_mousedown, false);
    canvas.addEventListener('touchstart', on_mousedown, false);
}

function signatureSave() {

    var canvas = document.getElementById("newSignature");
    // save canvas image as data url (png format by default)
    var dataURL = canvas.toDataURL("image/png");
    document.getElementById("saveSignature").src = dataURL;


};
function signaturePost() {
    var canvas = document.getElementById("newSignature");
    // save canvas image as data url (png format by default)
    document.getElementById('postSignature').value = canvas.toDataURL('image/png');
    document.forms["submit_signature"].submit()

}

/*
Reload page instead of this function:

function signatureClear() {


    var parent=document.getElementById("canvas");
    var child=document.getElementById("newSignature");
    parent.removeChild(child);

    signatureCapture();


}
*/

// http://stackoverflow.com/questions/11385471/save-canvas-image-post-the-data-string-to-php


function signatureSend() {
    var canvas = document.getElementById("newSignature");
    var dataURL = canvas.toDataURL("image/png");
    document.getElementById("saveSignature").src = dataURL;
    var sendemail = document.getElementById('sendemail').value;
    var replyemail = document.getElementById('replyemail').value;

var form = document.createElement("form");
form.setAttribute("action","upload_file.php");
form.setAttribute("enctype","multipart/form-data");
form.setAttribute("method","POST");
form.setAttribute("target","_self");
form.innerHTML = '<input type="text" name="image" value="'+dataURL+'"/>'+'<input type="email" name="email" value="'+sendemail+'"/>'+'<input type="email" name="replyemail" value="'+replyemail+'"/>';
form.submit();
}

I have implemented the code, and it works nicely in Chromechrome signature

but it scrambles in firefox

firefox signature

I'm using firefox 29.0.1 on HUAWEI mediapad 10 running android 4.1.2

Any thoughts?

Update: Here is a fiddle that shows the whole code at work: http://jsfiddle.net/3KHAf/

Was it helpful?

Solution

Based on the artifacts in the image, I suspect this is a bug the device graphics driver code and Firefox steps on it. Nothing unheard int the mobile world. Or it could be bug in Firefox itself too, but I find this option more unlikely.

I suggest the following steps

  • Check can you repeat the issue on other Android devices

  • Isolate the code causing graphical artifacts to a jsfiddle.net test case, where you have only the source code lines triggering the problem left. Share the link for others to test the issue.

  • Report a bug against Firefox Mobile https://bugzilla.mozilla.org/

If the bug is on Mozilla's side and it is repeatable, they usually get those fixed quite fast.

There is a #mobile channel on irc.mozilla.org where you can ask for further help.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top