SVG getScreenCTM() on FireFox

690 views Asked by At

GOAL

I am trying to build a signature pad in SVG. You can view Sample project here.

Description So far, it works in Chrome, Edge and Opera as desired but, in Firefox, getScreenCTM() doesn't account for the scale.

Research

I went through a bunch of documentation from bugzilla and a couple of posts here in SO such as SVG: GetScreenCTM() for nested SVG is different in Firefox but, still couldn't figure out how to fix my issue.

Problem

I've added a browse check to handle only Firefox (since all other browsers provides the desired result) which allows me to add extra code to fix the problem but, thus far, had no success. (SPSignature:416)

Reproduce the error

To reproduce the error, open the sample link in FireFox than, resize the box so it is at least 20% smaller as in fullscreen. You will see the mouseX/Y position change as scale changes.

I've tried to get the matrix transform from the group tag but, it returns similar result from the SVG. How do I calculate the CTM, so its result is similar/equal to Chrome?

Code

Source code here SPSignature:416

 _getCursorPoint(event)
{
    const svg = document.querySelector('.spsignature svg');
    let pt = svg.createSVGPoint();

    pt.x = event.clientX;
    pt.y = event.clientY;

    // firefox workaround:
    if (this._checkBrowser() === 'Firefox') {
        const matrix = this._decomposeMatrix(svg.getScreenCTM());

        let cood = { 
            x: event.layerX, 
            y: event.layerY
        };

        if (matrix.scaleX < 0.9 || matrix.scaleY < 0.9) {
            console.log('%c @todo: fix mouse position for FF on getScreenCTM().', 'background:#c00;color:#fff;padding:3px;');
        }

        return cood;
    }

    return pt.matrixTransform(svg.getScreenCTM().inverse());
}
1

There are 1 answers

4
Jay On

To "fix" the mouse XY problem on FF, I've used the root scale value to allow for the calculation of the cursor XY position.

The scale can be retrieved from the matrix based on https://gist.github.com/2052247.

Also, in FF, I've used the event.layerX and event.layerY instead of event.clientX and event.clientY for the initial mouse coordinate values.

So, instead of using matrixTransform(svg.getScreenCTM().inverse()) to return the calculated XY relative to the SVG, I've used the scale and layerXY to calculate the right XY position.