All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.build.modules.hero.js Maven / Gradle / Ivy

Go to download

A virtual DOM library with focus on simplicity, modularity, powerful features and performance.

The newest version!
const raf = (typeof window !== "undefined" && window.requestAnimationFrame) || setTimeout;
const nextFrame = function (fn) {
    raf(function () {
        raf(fn);
    });
};
function setNextFrame(obj, prop, val) {
    nextFrame(function () {
        obj[prop] = val;
    });
}
function getTextNodeRect(textNode) {
    let rect;
    if (document.createRange) {
        const range = document.createRange();
        range.selectNodeContents(textNode);
        if (range.getBoundingClientRect) {
            rect = range.getBoundingClientRect();
        }
    }
    return rect;
}
function calcTransformOrigin(isTextNode, textRect, boundingRect) {
    if (isTextNode) {
        if (textRect) {
            // calculate pixels to center of text from left edge of bounding box
            const relativeCenterX = textRect.left + textRect.width / 2 - boundingRect.left;
            const relativeCenterY = textRect.top + textRect.height / 2 - boundingRect.top;
            return `${relativeCenterX}px ${relativeCenterY}px`;
        }
    }
    return "0 0"; // top left
}
function getTextDx(oldTextRect, newTextRect) {
    if (oldTextRect && newTextRect) {
        return (oldTextRect.left +
            oldTextRect.width / 2 -
            (newTextRect.left + newTextRect.width / 2));
    }
    return 0;
}
function getTextDy(oldTextRect, newTextRect) {
    if (oldTextRect && newTextRect) {
        return (oldTextRect.top +
            oldTextRect.height / 2 -
            (newTextRect.top + newTextRect.height / 2));
    }
    return 0;
}
function isTextElement(elm) {
    return elm.childNodes.length === 1 && elm.childNodes[0].nodeType === 3;
}
let removed, created;
function pre() {
    removed = {};
    created = [];
}
function create(oldVnode, vnode) {
    const hero = vnode.data.hero;
    if (hero && hero.id) {
        created.push(hero.id);
        created.push(vnode);
    }
}
function destroy(vnode) {
    const hero = vnode.data.hero;
    if (hero && hero.id) {
        const elm = vnode.elm;
        vnode.isTextNode = isTextElement(elm); // is this a text node?
        vnode.boundingRect = elm.getBoundingClientRect(); // save the bounding rectangle to a new property on the vnode
        vnode.textRect = vnode.isTextNode
            ? getTextNodeRect(elm.childNodes[0])
            : null; // save bounding rect of inner text node
        const computedStyle = window.getComputedStyle(elm, undefined); // get current styles (includes inherited properties)
        vnode.savedStyle = JSON.parse(JSON.stringify(computedStyle)); // save a copy of computed style values
        removed[hero.id] = vnode;
    }
}
function post() {
    let i, id, newElm, oldVnode, oldElm, hRatio, wRatio, oldRect, newRect, dx, dy, origTransform, origTransition, newStyle, oldStyle, newComputedStyle, isTextNode, newTextRect, oldTextRect;
    for (i = 0; i < created.length; i += 2) {
        id = created[i];
        newElm = created[i + 1].elm;
        oldVnode = removed[id];
        if (oldVnode) {
            isTextNode = oldVnode.isTextNode && isTextElement(newElm); // Are old & new both text?
            newStyle = newElm.style;
            newComputedStyle = window.getComputedStyle(newElm, undefined); // get full computed style for new element
            oldElm = oldVnode.elm;
            oldStyle = oldElm.style;
            // Overall element bounding boxes
            newRect = newElm.getBoundingClientRect();
            oldRect = oldVnode.boundingRect; // previously saved bounding rect
            // Text node bounding boxes & distances
            if (isTextNode) {
                newTextRect = getTextNodeRect(newElm.childNodes[0]);
                oldTextRect = oldVnode.textRect;
                dx = getTextDx(oldTextRect, newTextRect);
                dy = getTextDy(oldTextRect, newTextRect);
            }
            else {
                // Calculate distances between old & new positions
                dx = oldRect.left - newRect.left;
                dy = oldRect.top - newRect.top;
            }
            hRatio = newRect.height / Math.max(oldRect.height, 1);
            wRatio = isTextNode ? hRatio : newRect.width / Math.max(oldRect.width, 1); // text scales based on hRatio
            // Animate new element
            origTransform = newStyle.transform;
            origTransition = newStyle.transition;
            if (newComputedStyle.display === "inline") {
                // inline elements cannot be transformed
                newStyle.display = "inline-block"; // this does not appear to have any negative side effects
            }
            newStyle.transition = origTransition + "transform 0s";
            newStyle.transformOrigin = calcTransformOrigin(isTextNode, newTextRect, newRect);
            newStyle.opacity = "0";
            newStyle.transform = `${origTransform}translate(${dx}px, ${dy}px) scale(${1 / wRatio}, ${1 / hRatio})`;
            setNextFrame(newStyle, "transition", origTransition);
            setNextFrame(newStyle, "transform", origTransform);
            setNextFrame(newStyle, "opacity", "1");
            // Animate old element
            for (const key in oldVnode.savedStyle) {
                // re-apply saved inherited properties
                if (String(parseInt(key)) !== key) {
                    const ms = key.substring(0, 2) === "ms";
                    const moz = key.substring(0, 3) === "moz";
                    const webkit = key.substring(0, 6) === "webkit";
                    if (!ms && !moz && !webkit) {
                        // ignore prefixed style properties
                        oldStyle[key] = oldVnode.savedStyle[key];
                    }
                }
            }
            oldStyle.position = "absolute";
            oldStyle.top = `${oldRect.top}px`; // start at existing position
            oldStyle.left = `${oldRect.left}px`;
            oldStyle.width = `${oldRect.width}px`; // Needed for elements who were sized relative to their parents
            oldStyle.height = `${oldRect.height}px`; // Needed for elements who were sized relative to their parents
            oldStyle.margin = "0"; // Margin on hero element leads to incorrect positioning
            oldStyle.transformOrigin = calcTransformOrigin(isTextNode, oldTextRect, oldRect);
            oldStyle.transform = "";
            oldStyle.opacity = "1";
            document.body.appendChild(oldElm);
            setNextFrame(oldStyle, "transform", `translate(${-dx}px, ${-dy}px) scale(${wRatio}, ${hRatio})`); // scale must be on far right for translate to be correct
            setNextFrame(oldStyle, "opacity", "0");
            oldElm.addEventListener("transitionend", function (ev) {
                if (ev.propertyName === "transform") {
                    document.body.removeChild(ev.target);
                }
            });
        }
    }
    removed = created = undefined;
}
export const heroModule = { pre, create, destroy, post };
//# sourceMappingURL=hero.js.map




© 2015 - 2025 Weber Informatics LLC | Privacy Policy