Compare transforms

Benchmark created on


Setup

const createAxisDelta = () => ({
    translate: 0,
    scale: 1,
    origin: 0,
    originPoint: 0,
})

const createDelta = () => ({
    x: createAxisDelta(),
    y: createAxisDelta(),
})

const treeScale = { x: 1, y: 1 }

const deltaCreate = createDelta()
const delta2 = Object.create(deltaCreate)
const prevDelta2 = Object.create(deltaCreate)

function buildProjectionTransform(
    delta,
    treeScale,
    latestTransform
) {
    let transform = ""

    /**
     * The translations we use to calculate are always relative to the viewport coordinate space.
     * But when we apply scales, we also scale the coordinate space of an element and its children.
     * For instance if we have a treeScale (the culmination of all parent scales) of 0.5 and we need
     * to move an element 100 pixels, we actually need to move it 200 in within that scaled space.
     */
    const xTranslate = delta.x.translate / treeScale.x
    const yTranslate = delta.y.translate / treeScale.y
    const zTranslate = latestTransform?.z || 0
    if (xTranslate || yTranslate || zTranslate) {
        transform = `translate3d(${xTranslate}px, ${yTranslate}px, ${zTranslate}px) `
    }

    /**
     * Apply scale correction for the tree transform.
     * This will apply scale to the screen-orientated axes.
     */
    if (treeScale.x !== 1 || treeScale.y !== 1) {
        transform += `scale(${1 / treeScale.x}, ${1 / treeScale.y}) `
    }

    if (latestTransform) {
        const { transformPerspective, rotate, rotateX, rotateY, skewX, skewY } =
            latestTransform
        if (transformPerspective)
            transform = `perspective(${transformPerspective}px) ${transform}`
        if (rotate) transform += `rotate(${rotate}deg) `
        if (rotateX) transform += `rotateX(${rotateX}deg) `
        if (rotateY) transform += `rotateY(${rotateY}deg) `
        if (skewX) transform += `skewX(${skewX}deg) `
        if (skewY) transform += `skewY(${skewY}deg) `
    }

    /**
     * Apply scale to match the size of the element to the size we want it.
     * This will apply scale to the element-orientated axes.
     */
    const elementScaleX = delta.x.scale * treeScale.x
    const elementScaleY = delta.y.scale * treeScale.y
    if (elementScaleX !== 1 || elementScaleY !== 1) {
        transform += `scale(${elementScaleX}, ${elementScaleY})`
    }

    return transform || "none"
}


let prevTransform = ""
const prevDelta = createDelta()
const delta = createDelta()

 function copyAxisDeltaInto(delta, originDelta) {
    delta.translate = originDelta.translate
    delta.scale = originDelta.scale
    delta.originPoint = originDelta.originPoint
    delta.origin = originDelta.origin
}

function updateDelta() {
	delta.y.originPoint = 200 * Math.random()
}

function updateDelta2() {
	delta2.y.originPoint = 200 * Math.random()
}

let transform = ""
let op = false

function hasAxisDeltaChanged(a, b) {
    return (
        a.translate !== b.translate ||
        a.scale !== b.scale ||
        a.originPoint !== b.originPoint ||
        a.origin !== b.origin
    )
}

Test runner

Ready to run.

Testing in
TestOps/sec
Compare string
updateDelta()

transform = buildProjectionTransform(delta, treeScale)

if (transform !== prevTransform) {
	op = !op
}

prevTransform = transform
ready
Compare and copy
updateDelta()

if (hasAxisDeltaChanged(delta.x, prevDelta.x) || hasAxisDeltaChanged(delta.y, prevDelta.y)) {
	op = !op
}

copyAxisDeltaInto(prevDelta.x, delta.x)
copyAxisDeltaInto(prevDelta.y, delta.y)
ready
Copy Object.create()
updateDelta2()

if (hasAxisDeltaChanged(delta2.x, prevDelta2.x) || hasAxisDeltaChanged(delta2.y, prevDelta2.y)) {
	op = !op
}

copyAxisDeltaInto(prevDelta2.x, delta2.x)
copyAxisDeltaInto(prevDelta2.y, delta2.y)
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.