MMLPositionMoveEvent extendsRemoteEvent
Received when a user moves after having entered the range of an m-position-probe.
<m-label y="5" z="-6" width="10" height="5" color="red" font-size="100">
</m-label>
<m-position-probe id="my-probe" z="3" range="5" y="1" debug="true" interval="100"></m-position-probe>
<script>
const labelElement = document.querySelector("m-label")
const positionProbe = document.querySelector("#my-probe");
positionProbe.addEventListener("positionmove", ({ detail }) => {
console.log(detail.documentRelative)
const text = `User at
x: ${detail.documentRelative.position.x.toString().substring(0, 6)},
y: ${detail.documentRelative.position.y.toString().substring(0, 6)},
z: ${detail.documentRelative.position.z.toString().substring(0, 6)}`
labelElement.setAttribute("content", text)
})
</script>
detailisReadonly
detail: {
documentRelative: PositionAndRotation
connectionId: number
}
Type declaration
- documentRelative:
PositionAndRotation
The location of the user relative to the target element.
- connectionId:
number
The unique numeric id of the connection that sent the event.
typeisReadonly
The **
type
** read-only property of the Event interface returns a string containing the event's type.
Literal: positionmove
Examples
Move Check
<m-label y="5" z="-6" width="10" height="5" color="red">
</m-label>
<m-position-probe id="my-probe" z="3" range="5" y="1" debug="true" interval="500"></m-position-probe>
<script>
const positionProbe = document.getElementById("my-probe");
const labelElement = document.querySelector("m-label")
function getShortenedPosition(position) {
return {
x: position.x.toString().substring(0, 6),
y: position.y.toString().substring(0, 6),
z: position.z.toString().substring(0, 6),
};
}
let lastKnownPosition = { x: 0, y: 0, z: 0 };
positionProbe.addEventListener("positionmove", ({ detail }) => {
// This is because of javascript floating point precision
const shortenedPosition = getShortenedPosition(detail.elementRelative.position);
// This is to prevent the label from updating every frame if the position is the same
if (JSON.stringify(lastKnownPosition) === JSON.stringify(shortenedPosition)) return;
lastKnownPosition = shortenedPosition;
const colors = ["black", "blue", "green", "white", "red", "purple"];
let selectedColor = Math.floor(Math.random() * colors.length);
// We don't want the color to be the same as the ground
while (colors[selectedColor] === labelElement.getAttribute("color")) {
selectedColor = Math.floor(Math.random() * colors.length);
}
labelElement.setAttribute("color", colors[selectedColor]);
});
</script>Rotation
<m-label y="5" z="-6" width="10" height="5" color="red" font-size="100">
</m-label>
<m-position-probe id="my-probe" z="3" range="5" y="1" debug="true" interval="100"></m-position-probe>
<script>
const labelElement = document.querySelector("m-label")
const positionProbe = document.querySelector("#my-probe");
positionProbe.addEventListener("positionmove", ({ detail }) => {
console.log(detail.documentRelative)
const text = `User at
x: ${detail.documentRelative.rotation.x.toString().substring(0, 6)},
y: ${detail.documentRelative.rotation.y.toString().substring(0, 6)},
z: ${detail.documentRelative.rotation.z.toString().substring(0, 6)}`
labelElement.setAttribute("content", text)
})
</script>
Moving Object
<m-group x="3" y="4">
<m-position-probe range="7" debug="true" id="my-probe" interval="100"></m-position-probe>
<m-group id="user-presence-holder"></m-group>
</m-group>
<script>
const connectedUsers = new Map();
const userPresenceHolder = document.getElementById("user-presence-holder");
const positionProbe = document.getElementById("my-probe");
function getOrCreateUser(connectionId, position, rotation) {
const user = connectedUsers.get(connectionId);
if (user) {
user.position = position;
user.rotation = rotation;
return user;
}
const userCube = document.createElement("m-cube");
userCube.setAttribute("collide", false);
userCube.setAttribute("width", 0.25);
userCube.setAttribute("height", 0.25);
userCube.setAttribute("depth", 0.25);
userCube.setAttribute("color", `#${Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, '0')}`);
userPresenceHolder.append(userCube);
const newUser = {
cube: userCube,
position,
rotation,
};
connectedUsers.set(connectionId, newUser);
return newUser;
}
function clearUser(connectionId) {
const user = connectedUsers.get(connectionId);
if (!user) return;
user.cube.remove();
connectedUsers.delete(connectionId);
}
function setCubePosition(connectionId, position, rotation) {
const user = getOrCreateUser(connectionId, position, rotation);
user.cube.setAttribute("x", position.x);
user.cube.setAttribute("y", position.y + 3);
user.cube.setAttribute("z", position.z);
user.cube.setAttribute("rx", rotation.x);
user.cube.setAttribute("ry", rotation.y);
user.cube.setAttribute("rz", rotation.z);
}
window.addEventListener("disconnected", (event) => {
const { connectionId } = event.detail;
clearUser(connectionId);
});
positionProbe.addEventListener("positionenter", (event) => {
const { connectionId, elementRelative, documentRelative } = event.detail;
setCubePosition(connectionId, elementRelative.position, elementRelative.rotation);
});
positionProbe.addEventListener("positionmove", (event) => {
const { connectionId, elementRelative, documentRelative } = event.detail;
/*
It's possible to receive an update without an explicit enter event if this user is already in the range of
this element when the document is reloaded. In this case, we need to create the user as if this is an
enter event.
*/
setCubePosition(connectionId, elementRelative.position, elementRelative.rotation);
});
positionProbe.addEventListener("positionleave", (event) => {
const { connectionId } = event.detail;
clearUser(connectionId);
});
</script>