-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3b89fd7
commit 9266e5f
Showing
27 changed files
with
619 additions
and
173 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<m-plane color="yellow" width="15" height="15" rx="-90"></m-plane> | ||
<m-light type="point" intensity="900" x="10" y="10" z="10"></m-light> | ||
|
||
<m-label width="5" y="1" rx="-45" z="3" content="This test tests snapshots of the state at intervals of document time. The document time is overridden in e2e tests"></m-label> | ||
|
||
<m-group id="timeline" y="0.25"> | ||
<m-cube width="15" height="0.25" depth="0.1" color="black"></m-cube> | ||
<m-cube width="1" x="-5.6" y="0.25" height="0.25" depth="0.1" z="0.1" color="green"></m-cube> | ||
<m-cube width="1" height="0.25" depth="0.1" z="0.1" color="red"> | ||
<m-attr-anim attr="x" start="-7" end="7" loop="true" duration="10000"></m-attr-anim> | ||
</m-cube> | ||
</m-group> | ||
|
||
<m-group x="0" y="2"> | ||
<m-label content="independent attributes" width="5" y="0.75" alignment="center" height="0.5"></m-label> | ||
<!-- Two independent attributes --> | ||
<m-cube width="5" x="-2.5" height="1" z="-0.1" depth="0.1" color="red"></m-cube> | ||
<m-cube width="5" x="2.5" height="1" z="-0.1" depth="0.1" color="green"></m-cube> | ||
<m-cube x="-4.25" depth="0.1" height="0.5" color="white" id="two-independent-attributes" onclick="this.setAttribute('x','4.25'); this.setAttribute('height','0.1');"> | ||
<m-attr-lerp attr="x" duration="4000"></m-attr-lerp> | ||
<m-attr-lerp attr="height" duration="2000"></m-attr-lerp> | ||
</m-cube> | ||
</m-group> | ||
|
||
<m-group x="0" y="3.75"> | ||
<m-label content="combined attributes - shadowed" width="5" y="0.75" alignment="center" height="0.5"></m-label> | ||
<!-- Combined attributes with an unused later sibling that is overridden --> | ||
<m-cube width="5" x="-2.5" height="1" z="-0.1" depth="0.1" color="red"></m-cube> | ||
<m-cube width="5" x="2.5" height="1" z="-0.1" depth="0.1" color="green"></m-cube> | ||
<m-cube x="-4.25" depth="0.1" height="0.5" color="white" id="combined-attributes-shadowed" onclick="this.setAttribute('x','4.25'); this.setAttribute('height','0.1');"> | ||
<m-attr-lerp attr="x,height" duration="4000"></m-attr-lerp> | ||
<m-attr-lerp attr="x" duration="2000"></m-attr-lerp> | ||
</m-cube> | ||
</m-group> | ||
|
||
<m-group x="0" y="5.5"> | ||
<m-label content="combined attributes - overridden" width="5" y="0.75" alignment="center" height="0.5"></m-label> | ||
<!-- Combined attributes, but with an earlier sibling that overrides the duration --> | ||
<m-cube width="5" x="-2.5" height="1" z="-0.1" depth="0.1" color="red"></m-cube> | ||
<m-cube width="5" x="2.5" height="1" z="-0.1" depth="0.1" color="green"></m-cube> | ||
<m-cube x="-4.25" depth="0.1" height="0.5" color="white" id="combined-attributes-overridden" onclick="this.setAttribute('x','4.25'); this.setAttribute('height','0.1');"> | ||
<m-attr-lerp attr="x" duration="2000"></m-attr-lerp> | ||
<m-attr-lerp attr="x,height" duration="4000"></m-attr-lerp> | ||
</m-cube> | ||
</m-group> | ||
|
||
<m-group x="0" y="7.25"> | ||
<m-label content="all attributes" width="5" y="0.75" alignment="center" height="0.5"></m-label> | ||
<!-- Explicitly specifying "all" attributes --> | ||
<m-cube width="5" x="-2.5" height="1" z="-0.1" depth="0.1" color="red"></m-cube> | ||
<m-cube width="5" x="2.5" height="1" z="-0.1" depth="0.1" color="green"></m-cube> | ||
<m-cube x="-4.25" depth="0.1" height="0.5" color="white" id="all-attributes" onclick="this.setAttribute('x','4.25'); this.setAttribute('height','0.1');"> | ||
<m-attr-lerp attr="all" duration="2000"></m-attr-lerp> | ||
</m-cube> | ||
</m-group> | ||
|
||
<m-group x="0" y="9"> | ||
<m-label content="all attributes (default)" width="5" y="0.75" alignment="center" height="0.5"></m-label> | ||
<!-- Default behaviour of not specifying "attr" is to have all attributes lerped --> | ||
<m-cube width="5" x="-2.5" height="1" z="-0.1" depth="0.1" color="red"></m-cube> | ||
<m-cube width="5" x="2.5" height="1" z="-0.1" depth="0.1" color="green"></m-cube> | ||
<m-cube x="-4.25" depth="0.1" height="0.5" color="white" id="all-attributes-default" onclick="this.setAttribute('x','4.25'); this.setAttribute('height','0.1');"> | ||
<m-attr-lerp duration="2000"></m-attr-lerp> | ||
</m-cube> | ||
</m-group> | ||
|
||
|
||
<m-group x="0" y="10.75"> | ||
<m-label content="no attributes" width="5" y="0.75" alignment="center" height="0.5"></m-label> | ||
<!-- Explicitly setting "attr" to empty (no lerping) --> | ||
<m-cube width="5" x="-2.5" height="1" z="-0.1" depth="0.1" color="red"></m-cube> | ||
<m-cube width="5" x="2.5" height="1" z="-0.1" depth="0.1" color="green"></m-cube> | ||
<m-cube x="-4.25" depth="0.1" height="0.5" color="white" id="no-attributes" onclick="this.setAttribute('x','4.25'); this.setAttribute('height','0.1');"> | ||
<m-attr-lerp attr="" duration="2000"></m-attr-lerp> | ||
</m-cube> | ||
</m-group> |
3 changes: 3 additions & 0 deletions
3
...-lerp-test-ts-m-attr-lerp-lerping-is-applied-according-to-attributes-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions
3
...-lerp-test-ts-m-attr-lerp-lerping-is-applied-according-to-attributes-2-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions
3
...-lerp-test-ts-m-attr-lerp-lerping-is-applied-according-to-attributes-3-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { clickElement, setDocumentTime, takeAndCompareScreenshot } from "./testing-utils"; | ||
|
||
type ExpectedStates = { [key: string]: { x: number; height: number } }; | ||
|
||
describe("m-attr-lerp", () => { | ||
test("lerping is applied according to attributes", async () => { | ||
const page = await __BROWSER_GLOBAL__.newPage(); | ||
|
||
await page.setViewport({ width: 1024, height: 1024 }); | ||
|
||
await page.goto("http://localhost:7079/attr-lerp.html/reset"); | ||
|
||
await page.waitForSelector("m-attr-lerp[attr='x']"); | ||
|
||
async function testExpectedStates(expectedStates: ExpectedStates) { | ||
for (const [id, expected] of Object.entries(expectedStates)) { | ||
const actualX = await page.evaluate((id) => { | ||
return (document.querySelector(`#${id}`) as any).getContainer().position.x; | ||
}, id); | ||
|
||
const actualHeight = await page.evaluate((id) => { | ||
return (document.querySelector(`#${id}`) as any).getCube().scale.y; | ||
}, id); | ||
|
||
expect(`${id}: x: ${actualX} height: ${actualHeight}`).toEqual( | ||
`${id}: x: ${expected.x} height: ${expected.height}`, | ||
); | ||
} | ||
} | ||
|
||
// Set the document time to 0 to use as a reference point for the start of the lerping | ||
await setDocumentTime(page, 0); | ||
|
||
await testExpectedStates({ | ||
"two-independent-attributes": { x: -4.25, height: 0.5 }, | ||
"combined-attributes-shadowed": { x: -4.25, height: 0.5 }, | ||
"combined-attributes-overridden": { x: -4.25, height: 0.5 }, | ||
"all-attributes": { x: -4.25, height: 0.5 }, | ||
"all-attributes-default": { x: -4.25, height: 0.5 }, | ||
"no-attributes": { x: -4.25, height: 0.5 }, | ||
}); | ||
|
||
await takeAndCompareScreenshot(page); | ||
|
||
// Click all of the cubes to trigger the lerping | ||
await clickElement(page, "#two-independent-attributes"); | ||
await clickElement(page, "#combined-attributes-shadowed"); | ||
await clickElement(page, "#combined-attributes-overridden"); | ||
await clickElement(page, "#all-attributes"); | ||
await clickElement(page, "#all-attributes-default"); | ||
await clickElement(page, "#no-attributes"); | ||
|
||
// Set the document time to 1000 to check the lerping | ||
await setDocumentTime(page, 1000); | ||
|
||
await testExpectedStates({ | ||
"two-independent-attributes": { x: -2.125, height: 0.3 }, | ||
"combined-attributes-shadowed": { x: -2.125, height: 0.4 }, | ||
"combined-attributes-overridden": { x: 0, height: 0.4 }, | ||
"all-attributes": { x: 0, height: 0.3 }, | ||
"all-attributes-default": { x: 0, height: 0.3 }, | ||
"no-attributes": { x: 4.25, height: 0.1 }, | ||
}); | ||
|
||
await takeAndCompareScreenshot(page); | ||
|
||
// Set the document time to 1000 to check the lerping | ||
await setDocumentTime(page, 5000); | ||
|
||
await testExpectedStates({ | ||
"two-independent-attributes": { x: 4.25, height: 0.1 }, | ||
"combined-attributes-shadowed": { x: 4.25, height: 0.1 }, | ||
"combined-attributes-overridden": { x: 4.25, height: 0.1 }, | ||
"all-attributes": { x: 4.25, height: 0.1 }, | ||
"all-attributes-default": { x: 4.25, height: 0.1 }, | ||
"no-attributes": { x: 4.25, height: 0.1 }, | ||
}); | ||
|
||
await takeAndCompareScreenshot(page); | ||
|
||
await page.close(); | ||
}, 60000); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import * as THREE from "three"; | ||
|
||
import { MElement } from "./MElement"; | ||
import { AttributeHandler, parseFloatAttribute } from "../utils/attribute-handling"; | ||
import { easingsByName } from "../utils/easings"; | ||
import { OrientedBoundingBox } from "../utils/OrientedBoundingBox"; | ||
|
||
const defaultAttribute: string = "all"; | ||
const defaultEasing = ""; | ||
const defaultLerpDuration = 1000; | ||
|
||
export class AttributeLerp extends MElement { | ||
static tagName = "m-attr-lerp"; | ||
|
||
private props = { | ||
attr: defaultAttribute, | ||
easing: defaultEasing, | ||
lerpDuration: defaultLerpDuration, | ||
}; | ||
|
||
private registeredParentAttachment: MElement | null = null; | ||
|
||
private static attributeHandler = new AttributeHandler<AttributeLerp>({ | ||
attr: (instance, newValue) => { | ||
if (instance.registeredParentAttachment) { | ||
instance.registeredParentAttachment.removeSideEffectChild(instance); | ||
} | ||
instance.props.attr = newValue !== null ? newValue : defaultAttribute; | ||
if (instance.registeredParentAttachment) { | ||
instance.registeredParentAttachment.addSideEffectChild(instance); | ||
} | ||
}, | ||
easing: (instance, newValue) => { | ||
instance.props.easing = newValue || defaultEasing; | ||
}, | ||
duration: (instance, newValue) => { | ||
instance.props.lerpDuration = Math.max(0, parseFloatAttribute(newValue, defaultLerpDuration)); | ||
}, | ||
}); | ||
|
||
static get observedAttributes(): Array<string> { | ||
return [...AttributeLerp.attributeHandler.getAttributes()]; | ||
} | ||
constructor() { | ||
super(); | ||
} | ||
|
||
protected enable() { | ||
// no-op | ||
} | ||
|
||
protected disable() { | ||
// no-op | ||
} | ||
|
||
protected getContentBounds(): OrientedBoundingBox | null { | ||
return null; | ||
} | ||
|
||
public getAnimatedAttributeName(): string | null { | ||
return this.props.attr; | ||
} | ||
|
||
public parentTransformed(): void { | ||
// no-op | ||
} | ||
|
||
public isClickable(): boolean { | ||
return false; | ||
} | ||
|
||
attributeChangedCallback(name: string, oldValue: string, newValue: string) { | ||
super.attributeChangedCallback(name, oldValue, newValue); | ||
AttributeLerp.attributeHandler.handle(this, name, newValue); | ||
} | ||
|
||
connectedCallback(): void { | ||
super.connectedCallback(); | ||
if (this.parentElement && this.parentElement instanceof MElement) { | ||
this.registeredParentAttachment = this.parentElement; | ||
this.registeredParentAttachment.addSideEffectChild(this); | ||
} | ||
} | ||
|
||
disconnectedCallback() { | ||
if (this.registeredParentAttachment) { | ||
this.registeredParentAttachment.removeSideEffectChild(this); | ||
} | ||
this.registeredParentAttachment = null; | ||
super.disconnectedCallback(); | ||
} | ||
|
||
public getColorValueForTime( | ||
windowTime: number, | ||
elementValueSetTime: number, | ||
elementValue: THREE.Color, | ||
previousValue: THREE.Color, | ||
) { | ||
const ratio = this.getLerpRatio(windowTime, elementValueSetTime); | ||
if (ratio >= 1) { | ||
return elementValue; | ||
} | ||
return new THREE.Color(previousValue).lerpHSL(elementValue, ratio); | ||
} | ||
|
||
public getFloatValueForTime( | ||
windowTime: number, | ||
elementValueSetTime: number, | ||
elementValue: number, | ||
previousValue: number, | ||
) { | ||
const from = previousValue; | ||
const to = elementValue; | ||
const ratio = this.getLerpRatio(windowTime, elementValueSetTime); | ||
if (ratio >= 1) { | ||
return to; | ||
} | ||
return from + (to - from) * ratio; | ||
} | ||
|
||
private getLerpRatio(windowTime: number, elementValueSetTime: number) { | ||
const duration = this.props.lerpDuration; | ||
const timePassed = (windowTime || 0) - elementValueSetTime; | ||
const ratioOfTimePassed = Math.min(timePassed / duration, 1); | ||
const easing = this.props.easing; | ||
let ratio; | ||
const easingFunction = easingsByName[easing]; | ||
if (easingFunction) { | ||
ratio = easingFunction(ratioOfTimePassed, 0, 1, 1); | ||
} else { | ||
ratio = ratioOfTimePassed; | ||
} | ||
return ratio; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.