Skip to content

Commit

Permalink
Add affordance draft to 3D scenes
Browse files Browse the repository at this point in the history
  • Loading branch information
otacke committed Aug 28, 2024
1 parent f9842ae commit 389c540
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 0 deletions.
119 changes: 119 additions & 0 deletions scripts/components/Scene/SceneTypes/ThreeSixtyScene.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default class ThreeSixtyScene extends React.Component {
this.props = props;

this.sceneRef = React.createRef();
this.affordancePointerRef = React.createRef();
this.renderedInteractions = 0;

this.state = {
Expand All @@ -38,6 +39,8 @@ export default class ThreeSixtyScene extends React.Component {
this.handleFirstRender = this.handleFirstRender.bind(this);
this.handleSceneMoveStart = this.handleSceneMoveStart.bind(this);
this.handleSceneMoveStop = this.handleSceneMoveStop.bind(this);

this.terminateAffordance = this.terminateAffordance.bind(this);
}

/**
Expand Down Expand Up @@ -80,15 +83,126 @@ export default class ThreeSixtyScene extends React.Component {
isRendered: true
});

this.registerAffordance({
intervalMs: 7500
});

this.focusScene();
}

/**
* Register affordance.
* @param {object} [params] Parameters.
* @param {number} [params.intervalMs] Interval in milliseconds.
* @param {boolean} [params.once] If true, run only once.
*/
registerAffordance(params = {}) {
if (typeof params.intervalMs !== 'number' || params.intervalMs < 1000) {
params.intervalMs = 2000;
}

window.clearTimeout(this.affordanceStartTimeout);
this.affordanceStartTimeout = window.setInterval(() => {
if (this.preAffordanceCameraPosition) {
return; // Affordance already started
}

this.startAffordance({ once: params.once });
}, params.intervalMs);

document.addEventListener('click', this.terminateAffordance, { once: true });
document.addEventListener('keydown', this.terminateAffordance, { once: true });
}

/**
* Start affordance animation.
* @param {object} [params] Parameters.
* @param {boolean} [params.once] If true, run only once.
*/
startAffordance(params = {}) {
params.once = params.once || false;

this.preAffordanceCameraPosition = this.props.threeSixty.getCurrentPosition();
this.affordanceCounter = 0;

this.affordancePointerRef.current.classList.remove('display-none');

this.affordanceAnimationTimeout = window.setInterval(() => {
this.animateAffordance({ once: params.once });
}, 25); // 40 fps
}

/**
* Animate the affordance.
* @param {object} [params] Parameters.
* @param {boolean} [params.once] If true, terminate after one animation.
* @param {number} [params.displacementFactor] Displacement factor.
*/
animateAffordance(params = {}) {
params.displacementFactor = params.displacementFactor ?? 0.5;

this.affordanceCounter += Math.PI / 45;

if (this.affordanceCounter >= 2 * Math.PI) {
if (params.once) {
this.terminateAffordance();
}
else {
this.stopAffordance();
}

return;
}

const translation = Math.sin(this.affordanceCounter) * params.displacementFactor;

this.affordancePointerRef.current.style.translate = `${-10 * translation}%`;
this.affordanceYaw = this.preAffordanceCameraPosition.yaw + translation / 10;

// Setting this by updating state seems to be too slow
this.props.threeSixty.setCameraPosition(this.affordanceYaw, this.preAffordanceCameraPosition.pitch);
}

/**
* Stop affordance animation.
*/
stopAffordance() {
clearTimeout(this.affordanceAnimationTimeout);

this.affordancePointerRef.current.classList.add('display-none');
this.affordancePointerRef.current.style.translate = '';

if (!this.preAffordanceCameraPosition) {
return;
}

this.props.threeSixty.setCameraPosition(
this.preAffordanceCameraPosition.yaw, this.preAffordanceCameraPosition.pitch
);

delete this.affordanceCounter;
delete this.preAffordanceCameraPosition;
}

/**
* Terminate affordance animation.
*/
terminateAffordance() {
window.clearTimeout(this.affordanceStartTimeout);
this.stopAffordance();

document.removeEventListener('click', this.terminateAffordance);
document.removeEventListener('keydown', this.terminateAffordance);
}

/**
* Handle dragging scene started.
* @param {H5P.Event} event Event.
* @returns {boolean|undefined} False, when dragging context menu or context menu children.
*/
handleSceneMoveStart(event) {
this.terminateAffordance();

this.startPosition = this.props.threeSixty.getCurrentPosition();

if (!this.context.extras.isEditor || event.data.isCamera) {
Expand Down Expand Up @@ -653,6 +767,11 @@ export default class ThreeSixtyScene extends React.Component {
</div>
</div>
}
<div
ref={this.affordancePointerRef}
className="affordance-pointer display-none"
>
</div>
</div>
);
}
Expand Down
26 changes: 26 additions & 0 deletions scripts/components/Scene/SceneTypes/ThreeSixtyScene.scss
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,32 @@
width: 7em;
}
}

.affordance-pointer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;

&.display-none {
display: none;
}

&::before {
content: " ";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 9em;
height: 9em;
background: url('../../../assets/moving-icon.svg');
background-size: 100% 100%;
font-size: 0.5em;
}
}
}

@keyframes spinning {
Expand Down

0 comments on commit 389c540

Please sign in to comment.