@pmndrs/uikit
Version:
Build performant 3D user interfaces with Three.js and yoga.
117 lines (116 loc) • 3.91 kB
JavaScript
import { abortableEffect, readReactive } from './utils.js';
export const reversePainterSortStableCacheKey = Symbol('reverse-painter-sort-stable-cache-key');
export const orderInfoKey = Symbol('order-info-key');
export function reversePainterSortStable(a, b) {
if (a.groupOrder !== b.groupOrder) {
return a.groupOrder - b.groupOrder;
}
if (a.renderOrder !== b.renderOrder) {
return a.renderOrder - b.renderOrder;
}
let az = a.z;
let bz = b.z;
const aRootSignal = a.object[reversePainterSortStableCacheKey];
const bRootSignal = b.object[reversePainterSortStableCacheKey];
if (aRootSignal != null) {
const root = aRootSignal.peek();
root.reversePainterSortStableCache ??= az;
az = root.reversePainterSortStableCache;
}
if (bRootSignal != null) {
const root = bRootSignal.peek();
root.reversePainterSortStableCache ??= bz;
bz = root.reversePainterSortStableCache;
}
if (aRootSignal != null && aRootSignal.peek() === bRootSignal?.peek()) {
return compareOrderInfo(a.object[orderInfoKey].value, b.object[orderInfoKey].value);
}
//default z comparison
return az !== bz ? bz - az : a.id - b.id;
}
//the following order tries to represent the most common element order of the respective element types (e.g. panels are most likely the background element)
export const ElementType = {
Panel: 0, //render first
Image: 1,
Content: 2,
Custom: 3,
Text: 4, //render last
};
export function compareOrderInfo(o1, o2) {
if (o1 == null || o2 == null) {
return 0;
}
let dif = o1.majorIndex - o2.majorIndex;
if (dif != 0) {
return dif;
}
dif = o1.minorIndex - o2.minorIndex;
if (dif != 0) {
return dif;
}
dif = o1.elementType - o2.elementType;
if (dif != 0) {
return dif;
}
return o1.patchIndex - o2.patchIndex;
}
export function setupOrderInfo(target, properties, zIndexKey, type, instancedGroupDependencies, basisOrderInfoSignal, abortSignal) {
abortableEffect(() => {
if (basisOrderInfoSignal.value === undefined) {
target.value = undefined;
return;
}
const basisOrderInfo = basisOrderInfoSignal.value;
//similiar but not the same as in css
const majorIndex = properties.value[zIndexKey] ?? basisOrderInfo?.majorIndex ?? 0;
let minorIndex;
let patchIndex;
if (basisOrderInfo == null) {
minorIndex = 0;
patchIndex = 0;
}
else if (type > basisOrderInfo.elementType) {
minorIndex = basisOrderInfo.minorIndex;
patchIndex = 0;
}
else if (type != basisOrderInfo.elementType ||
!shallowEqualRecord(readReactive(instancedGroupDependencies), readReactive(basisOrderInfo.instancedGroupDependencies))) {
minorIndex = basisOrderInfo.minorIndex + 1;
patchIndex = 0;
}
else {
minorIndex = basisOrderInfo.minorIndex;
patchIndex = basisOrderInfo.patchIndex + 1;
}
patchIndex += properties.value['zIndexOffset'] ?? 0;
target.value = {
instancedGroupDependencies,
elementType: type,
majorIndex,
minorIndex,
patchIndex,
};
}, abortSignal);
}
function shallowEqualRecord(r1, r2) {
if (r1 === r2) {
return true;
}
if (r1 == null || r2 == null) {
return false;
}
//i counts the number of keys in r1
let i = 0;
for (const key in r1) {
if (r1[key] != r2[key]) {
return false;
}
++i;
}
return i === Object.keys(r2).length;
}
export function setupRenderOrder(target, root, orderInfo) {
;
target[reversePainterSortStableCacheKey] = root;
target[orderInfoKey] = orderInfo;
}