Skip to content

Commit

Permalink
add jank to fix jank
Browse files Browse the repository at this point in the history
  • Loading branch information
OrionReed committed Dec 11, 2024
1 parent 164acc3 commit 1f883fe
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 9 deletions.
14 changes: 10 additions & 4 deletions demo/projector.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@

const projector = document.querySelector('folk-projector');

function createSpreadsheetEditor(shape) {
function XYCell(shape) {
const editor = document.createElement('div');
const xInput = document.createElement('input');
const yInput = document.createElement('input');
xInput.type = 'number';
yInput.type = 'number';

[xInput, yInput].forEach((input) => (input.type = 'number'));
xInput.value = shape.x;
yInput.value = shape.y;

Expand All @@ -78,15 +79,20 @@

const shapes = document.querySelectorAll('folk-shape');
shapes.forEach((shape) => {
projector.mapping(shape, createSpreadsheetEditor);
console.log(shape);
projector.mapping(shape, XYCell);
});

document.addEventListener('keydown', (event) => {
if (event.key === 'v') {
projector.project();
}
});

document.addEventListener('click', (event) => {
if (event.target === document.body) {
projector.project();
}
});
</script>
</body>
</html>
46 changes: 41 additions & 5 deletions src/folk-projector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,46 @@ export class FolkProjector extends HTMLElement {
display: flex;
flex-wrap: wrap;
position: absolute;
border-radius: 4px;
overflow: hidden;
}
div input:first-of-type {
border-right: 2px solid lightgray;
}
div input {
background-color: #36454f;
color: white;
width: 50%;
min-width: 0;
font-size: 12px;
box-sizing: border-box;
border: none;
text-align: center;
}
`;
this.appendChild(style);
}

// TODO: avoid this kind of hack
#maintainProjectedPositions() {
if (!this.#isProjecting) return;

const shapes = Array.from(this.children).filter((el): el is FolkShape => el instanceof FolkShape);
const mappedElements = shapes
.map((shape) => this.#mappedElements.get(shape))
.filter((el): el is HTMLElement => el !== null);

shapes.forEach((shape, i) => {
const mappedEl = mappedElements[i];
// Restore the projected position before paint
shape.style.transform = mappedEl.style.transform;
shape.style.width = mappedEl.style.width;
shape.style.height = mappedEl.style.height;
});

requestAnimationFrame(() => this.#maintainProjectedPositions());
}

mapping(shape: FolkShape, mappingFn: (element: FolkShape) => HTMLElement) {
const mappedEl = mappingFn(shape);
const rect = shape.getTransformDOMRect();
Expand All @@ -55,14 +84,15 @@ export class FolkProjector extends HTMLElement {
mappedEl.style.transform = shape.style.transform;
mappedEl.style.transformOrigin = '0 0';
mappedEl.style.opacity = '0';
mappedEl.style.pointerEvents = 'all';
mappedEl.style.pointerEvents = 'none';

this.appendChild(mappedEl);
this.#mappedElements.set(shape, mappedEl);
}

async project(spacing = 20) {
if (this.#isTransitioning) return;

this.#isTransitioning = true;

const shapes = Array.from(this.children).filter((el): el is FolkShape => el instanceof FolkShape);
Expand All @@ -71,9 +101,6 @@ export class FolkProjector extends HTMLElement {
.map((shape) => this.#mappedElements.get(shape))
.filter((el): el is HTMLElement => el !== null);

// Ensure elements are painted before transition
await new Promise(requestAnimationFrame);

const CELL_WIDTH = 100;
const CELL_HEIGHT = 50;
const X_OFFSET = 20;
Expand Down Expand Up @@ -127,6 +154,10 @@ export class FolkProjector extends HTMLElement {
shape.style.transform = newTransform;
shape.style.width = `${newRect.width}px`;
shape.style.height = `${newRect.height}px`;
if (this.#isProjecting) {
shape.blur();
shape.style.zIndex = '0';
}
const mappedEl = mappedElements[i];
if (mappedEl) {
mappedEl.style.transform = newTransform;
Expand All @@ -141,11 +172,16 @@ export class FolkProjector extends HTMLElement {
this.#isTransitioning = false;
shapes.forEach((shape, i) => {
shape.style.viewTransitionName = '';
shape.style.pointerEvents = this.#isProjecting ? 'none' : 'all';
mappedElements[i].style.viewTransitionName = '';
mappedElements[i].style.pointerEvents = this.#isProjecting ? 'all' : 'none';
});
});
}

this.#isProjecting = !this.#isProjecting;

if (this.#isProjecting) {
this.#maintainProjectedPositions();
}
}
}

0 comments on commit 1f883fe

Please sign in to comment.