diff --git a/packages/visx-event/src/localPointGeneric.ts b/packages/visx-event/src/localPointGeneric.ts index b6675f974..93588c442 100644 --- a/packages/visx-event/src/localPointGeneric.ts +++ b/packages/visx-event/src/localPointGeneric.ts @@ -3,6 +3,29 @@ import { EventType } from './types'; import { isSVGElement, isSVGGraphicsElement, isSVGSVGElement } from './typeGuards'; import getXAndYFromEvent from './getXAndYFromEvent'; +const CHILD_ID = '__visx-child-ctm-workaround'; + +/** + * Gets the screen CTM applied to children. + * + * Normally this is equivalent to `node.getScreenCTM()` but + * when `node` is a nested `SVGSVGElement` Firefox returns + * the screen CTM of the parent `SVGSVGElement`. See: + * - https://bugzilla.mozilla.org/show_bug.cgi?id=1344537 + * - https://bugzilla.mozilla.org/show_bug.cgi?id=1446011 + */ +function getChildScreenCTM(node: SVGGraphicsElement): DOMMatrix | null { + if (!(node instanceof SVGSVGElement)) return node.getScreenCTM(); + let child = node.children.namedItem(CHILD_ID) as SVGGraphicsElement; + if (child === null) { + child = document.createElementNS('http://www.w3.org/2000/svg', 'g'); + child.id = CHILD_ID; + node.appendChild(child); + } + const screenCTM = child.getScreenCTM(); + return screenCTM; +} + export default function localPoint(node: Element, event: EventType) { if (!node || !event) return null; @@ -10,7 +33,7 @@ export default function localPoint(node: Element, event: EventType) { // find top-most SVG const svg = isSVGElement(node) ? node.ownerSVGElement : node; - const screenCTM = isSVGGraphicsElement(svg) ? svg.getScreenCTM() : null; + const screenCTM = isSVGGraphicsElement(svg) ? getChildScreenCTM(svg) : null; if (isSVGSVGElement(svg) && screenCTM) { let point = svg.createSVGPoint(); diff --git a/packages/visx-vendor/scripts/buildVendor/index.ts b/packages/visx-vendor/scripts/buildVendor/index.ts index 06b7b8225..63f6cbace 100644 --- a/packages/visx-vendor/scripts/buildVendor/index.ts +++ b/packages/visx-vendor/scripts/buildVendor/index.ts @@ -72,10 +72,10 @@ async function build() { const { stdout, stderr } = await exec( `babel \ - --config-file ${BABEL_CONFIG_FILE} \ + --config-file "${BABEL_CONFIG_FILE}" \ --only ${transpileGlob} \ - --out-dir ${VENDOR_CJS_PATH} \ - ${NODE_MODULES_PATH}`, + --out-dir "${VENDOR_CJS_PATH}" \ + "${NODE_MODULES_PATH}"`, ); if (stdout) {