Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React nested SVG elements break the position #1011

Open
maloguertin opened this issue Sep 12, 2023 · 6 comments
Open

React nested SVG elements break the position #1011

maloguertin opened this issue Sep 12, 2023 · 6 comments
Labels
bug Something isn't working complete question Further information is requested
Milestone

Comments

@maloguertin
Copy link
Contributor

Environments

Description

Nesting SVG elements breaks the positioning of moveable. getElementInfo(target) returns NaN for most matrixes.

@daybrush daybrush added the question Further information is requested label Sep 19, 2023
@daybrush
Copy link
Owner

@maloguertin

The address code appears to have changed. Can you show which svg is causing the problem?

@maloguertin
Copy link
Contributor Author

maloguertin commented Sep 27, 2023

@maloguertin
Copy link
Contributor Author

I played in moveable code a little bit and was able to get it somewhat working but I'm afraid it would break other stuff. From what I have seen there seem to be some probles in these areas:

//packages/react-moveable/src/utils.tsx

export function getSVGViewBox(el: SVGSVGElement) {
    const clientWidth = el.clientWidth;
    const clientHeight = el.clientHeight;

    if (!el) {
        return { x: 0, y: 0, width: 0, height: 0, clientWidth, clientHeight };
    }
    const viewBox = el.viewBox;
    const baseVal = (viewBox && viewBox.baseVal) || { x: 0, y: 0, width: 0, height: 0 }; 👈  it seems like nested SVGs will always return { x: 0, y: 0, width: 0, height: 0 }; for their baseVal 

    return {
        x: baseVal.x,
        y: baseVal.y,
        width: baseVal.width || clientWidth,
        height: baseVal.height || clientHeight,
        clientWidth,
        clientHeight,
    };
}

export function getSize( 👈 this function returns invalid values for a nested SVG, I tried playing around with instead returning the size of it's ownerSVGElement
    target?: SVGElement | HTMLElement | null,
): ElementSizes {
    const hasOffset = target && !isUndefined((target as any).offsetWidth);

    let offsetWidth = 0;
    let offsetHeight = 0;
    let clientWidth = 0;
    let clientHeight = 0;
    let cssWidth = 0;
    let cssHeight = 0;
    let contentWidth = 0;
    let contentHeight = 0;

    let minWidth = 0;
    let minHeight = 0;
    let minOffsetWidth = 0;
    let minOffsetHeight = 0;

    let maxWidth = Infinity;
    let maxHeight = Infinity;
    let maxOffsetWidth = Infinity;
    let maxOffsetHeight = Infinity;
    let inlineCSSWidth = 0;
    let inlineCSSHeight = 0;
    let svg = false;

    if (target) {
        if (!hasOffset && target!.tagName.toLowerCase() !== "svg") {
            // check svg elements
            const bbox = (target as SVGGraphicsElement).getBBox();

            svg = true;
            offsetWidth = bbox.width;
            offsetHeight = bbox.height;
            cssWidth = offsetWidth;
            cssHeight = offsetHeight;
            contentWidth = offsetWidth;
            contentHeight = offsetHeight;
            clientWidth = offsetWidth;
            clientHeight = offsetHeight;
        } else {
            // check html elements
            const getStyle = getCachedStyle(target);
            const targetStyle = target.style;
            const boxSizing = getStyle("boxSizing") === "border-box";
            const borderLeft = parseFloat(getStyle("borderLeftWidth")) || 0;
            const borderRight = parseFloat(getStyle("borderRightWidth")) || 0;
            const borderTop = parseFloat(getStyle("borderTopWidth")) || 0;
            const borderBottom = parseFloat(getStyle("borderBottomWidth")) || 0;
            const paddingLeft = parseFloat(getStyle("paddingLeft")) || 0;
            const paddingRight = parseFloat(getStyle("paddingRight")) || 0;
            const paddingTop = parseFloat(getStyle("paddingTop")) || 0;
            const paddingBottom = parseFloat(getStyle("paddingBottom")) || 0;

            const horizontalPadding = paddingLeft + paddingRight;
            const verticalPadding = paddingTop + paddingBottom;
            const horizontalBorder = borderLeft + borderRight;
            const verticalBorder = borderTop + borderBottom;
            const horizontalOffset = horizontalPadding + horizontalBorder;
            const verticalOffset = verticalPadding + verticalBorder;
            const position = getStyle("position");

            let containerWidth = 0;
            let containerHeight = 0;

            // SVGSVGElement, HTMLElement
            if ("clientLeft" in target) {
                let parentElement: HTMLElement | null = null;

                if (position === "absolute") {
                    const offsetInfo = getOffsetInfo(target, getDocumentBody(target));
                    parentElement = offsetInfo.offsetParent;

                } else {
                    parentElement = target.parentElement;
                }
                if (parentElement) {
                    const getParentStyle = getCachedStyle(parentElement);

                    containerWidth = parseFloat(getParentStyle("width"));
                    containerHeight = parseFloat(getParentStyle("height"));
                }
            }
            minWidth = Math.max(
                horizontalPadding,
                convertUnitSize(getStyle("minWidth"), containerWidth) || 0,
            );
            minHeight = Math.max(
                verticalPadding,
                convertUnitSize(getStyle("minHeight"), containerHeight) || 0,
            );
            maxWidth = convertUnitSize(getStyle("maxWidth"), containerWidth);
            maxHeight = convertUnitSize(getStyle("maxHeight"), containerHeight);

            if (isNaN(maxWidth)) {
                maxWidth = Infinity;
            }
            if (isNaN(maxHeight)) {
                maxHeight = Infinity;
            }
            inlineCSSWidth = convertUnitSize(targetStyle.width, 0) || 0;
            inlineCSSHeight = convertUnitSize(targetStyle.height, 0) || 0;
            cssWidth = parseFloat(getStyle("width")) || 0;
            cssHeight = parseFloat(getStyle("height")) || 0;


            contentWidth = abs(cssWidth - inlineCSSWidth) < 1
                ? between(minWidth, inlineCSSWidth || cssWidth, maxWidth)
                : cssWidth;
            contentHeight = abs(cssHeight - inlineCSSHeight) < 1
                ? between(minHeight, inlineCSSHeight || cssHeight, maxHeight)
                : cssHeight;

            offsetWidth = contentWidth;
            offsetHeight = contentHeight;
            clientWidth = contentWidth;
            clientHeight = contentHeight;

            if (boxSizing) {
                maxOffsetWidth = maxWidth;
                maxOffsetHeight = maxHeight;
                minOffsetWidth = minWidth;
                minOffsetHeight = minHeight;
                contentWidth = offsetWidth - horizontalOffset;
                contentHeight = offsetHeight - verticalOffset;
            } else {
                maxOffsetWidth = maxWidth + horizontalOffset;
                maxOffsetHeight = maxHeight + verticalOffset;
                minOffsetWidth = minWidth + horizontalOffset;
                minOffsetHeight = minHeight + verticalOffset;
                offsetWidth = contentWidth + horizontalOffset;
                offsetHeight = contentHeight + verticalOffset;
            }
            clientWidth = contentWidth + horizontalPadding;
            clientHeight = contentHeight + verticalPadding;
        }
    }

    return {
        svg,
        offsetWidth,
        offsetHeight,
        clientWidth,
        clientHeight,
        contentWidth,
        contentHeight,
        inlineCSSWidth,
        inlineCSSHeight,
        cssWidth,
        cssHeight,
        minWidth,
        minHeight,
        maxWidth,
        maxHeight,
        minOffsetWidth,
        minOffsetHeight,
        maxOffsetWidth,
        maxOffsetHeight,
    };
}

@daybrush daybrush added the bug Something isn't working label Sep 30, 2023
@daybrush
Copy link
Owner

@maloguertin

It may not be a normal structure, but I will try to modify it.

Thank you.

@daybrush daybrush added this to the 0.51.3 milestone Sep 30, 2023
@maloguertin
Copy link
Contributor Author

@maloguertin

It may not be a normal structure, but I will try to modify it.

Thank you.

You mean nested SVG may not be a normal structure?

daybrush added a commit that referenced this issue Oct 4, 2023
@daybrush
Copy link
Owner

@maloguertin

  • croact-moveable 0.8.0
  • @moveable/helper 0.1.3
  • lit-moveable 0.29.0
  • moveable 0.52.0
  • preact-moveable 0.54.0
  • react-moveable 0.55.0
  • svelte-moveable 0.44.0
  • vue-moveable 2.0.0-beta.86
  • vue3-moveable 0.27.0
  • ngx-moveable 0.49.0

moveable's new version is released. Check it again.

I think svg within svg has a strange structure.

A slightly more complicated calculation formula has been added. There may be a problem, but if there is, please let me know in the comments.

<svg>
    <svg>...</svg>
</svg>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working complete question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants