function openCustomSignature(titleText, helpUrl, localization, onConfirmed) {
    $().customModal({
        onOpen: function () {
            let $canvas = $("#signatureModal").find("#signatureCanvas");
            let $resetButton = $("#signatureModal").find(".custom-signature-reset");
            initializeSignatureCanvas($canvas, $resetButton);
        },
        destroyOnClose: true,
        title: titleText,
        showCloseButton: true,
        openOnCreate: true,
        help: helpUrl,
        id: "signatureModal",
        type: "modal",
        content: "<div class='custom-signature'><canvas id='signatureCanvas'></canvas><button class='custom-signature-reset btn btn-ghost'><i class='fa fa-undo'></i> " + localization.signAgain + "</button></div>",
        buttons: [
            {
                icon: 'fa fa-times',
                text: localization.cancel,
                closeOnAction: true,
                type: 'ghost'
            },
            {
                icon: 'fa fa-check',
                text: localization.confirm,
                action: async function () {
                    let cropedImage = cropImageFromCanvas($("#signatureModal").find("#signatureCanvas")[0].getContext('2d'));
                    if (onConfirmed) await onConfirmed(cropedImage);
                },
                closeOnAction: true,
                type: 'primary'
            }
        ]
    });
}

function initializeSignatureCanvas($canvasElement, $resetButton) {
    if ($canvasElement == undefined || $canvasElement.length == 0) return;

    let canvas = $canvasElement[0];
    let parent = $canvasElement.parent()[0];
    let signatureCanvasContext = canvas.getContext('2d');

    signatureCanvasContext.canvas.width = parent.clientWidth - 2;
    signatureCanvasContext.canvas.height = parent.clientHeight - 2;

    let canvasOffset = canvas.getBoundingClientRect();
    let coordinates;
    let started = false;

    $canvasElement.on("mousemove touchmove", (e) => { if (started) coordinates = drawOnCanvas(e, canvasOffset, signatureCanvasContext, coordinates); });
    $canvasElement.on("mousedown touchstart", () => { started = true; });
    $canvasElement.on("mouseup touchend", () => { started = false; coordinates = undefined; });

    window.addEventListener("resize", () => {
        signatureCanvasContext.canvas.width = parent.clientWidth - 2;
        signatureCanvasContext.canvas.height = parent.clientHeight - 2;
        canvasOffset = canvas.getBoundingClientRect();
    });
    $resetButton.on("click", () => { signatureCanvasContext.clearRect(0, 0, canvas.width, canvas.height); });
}

function drawOnCanvas(event, canvasOffset, context, coordinates) {
    if (!coordinates) return getMouseTouchCoordinates(event, canvasOffset);

    context.beginPath();
    context.lineWidth = 2;
    context.lineCap = "round";
    context.strokeStyle = "#000000";
    context.moveTo(coordinates.x, coordinates.y);

    let newCoordinates = getMouseTouchCoordinates(event, canvasOffset);

    context.lineTo(newCoordinates.x, newCoordinates.y);
    context.stroke();

    return newCoordinates;
}

function getMouseTouchCoordinates(event, offset) {
    if (event && event.type && event.type === "touchmove") {
        var touch = event.originalEvent.touches[0] || event.originalEvent.changedTouches[0];
        return { x: touch.pageX - offset.left, y: touch.pageY - offset.top };
    }

    return { x: event.clientX - offset.left, y: event.clientY - offset.top };
}

function cropImageFromCanvas(ctx) {
    var canvas = ctx.canvas,
        w = canvas.width, h = canvas.height,
        pix = { x: [], y: [] },
        imageData = ctx.getImageData(0, 0, canvas.width, canvas.height),
        x, y, index;

    for (y = 0; y < h; y++) {
        for (x = 0; x < w; x++) {
            index = (y * w + x) * 4;
            if (imageData.data[index + 3] > 0) {
                pix.x.push(x);
                pix.y.push(y);
            }
        }
    }
    pix.x.sort(function (a, b) { return a - b });
    pix.y.sort(function (a, b) { return a - b });
    var n = pix.x.length - 1;

    w = 1 + pix.x[n] - pix.x[0];
    h = 1 + pix.y[n] - pix.y[0];
    var cut = ctx.getImageData(pix.x[0], pix.y[0], w, h);

    canvas.width = w;
    canvas.height = h;
    ctx.putImageData(cut, 0, 0);

    return canvas.toDataURL("image/png");
}