Introduction
1. Embedding SmartShape in an iframe¶
SmartShape can be embedded in an existing platform within an iframe like so:
<iframe
src="https://smartshape.io.test/app#autoplay=true"
height="800"
width="1200"
title="SmartShape client"
id="smartshape"
>
</iframe>
This is enough to embed SmartShape, however, please be aware of the various limitations and security constraints applied by most web browsers.
Most importantly, SmartShape sets the content-security-policy
header to frame-ancestors 'self'
.
So it must be served from the same origin (same scheme, host and port) as the parent page.
2. Communicating with an embedded SmartShape player¶
When the SmartShape client is embedded in an iframe
, the parent page can communicate with it using the postMessage
function exposed on the iframe
.
The communication is based on messages that update the internal state (a JSON document) shared between the 3D player and the UI.
2.1. Sending messages to the SmartShape player¶
To send a message to a SmartShape player embedded like in the previous section, the parent page must do:
let focusNodeMessage = {
"type": "patchState",
"data": [
{
"op": "replace",
"path": "/scene/focusedNode/id",
"value": "6581a4bb857abd8d44eda631"
}
]
};
document.getElementById("smartshape").contentWindow.postMessage(JSON.stringify(focusNodeMessage), "https://smartshape.io.test");
The message to send to SmartShape is a stringified JSON object with the following structure:
And the data
field must contain a list of JSON Patches that will be applied to the state.
2.2. Receiving messages from the SmartShape player¶
To receive messages from SmartShape, the parent page must do two things:
- Add an event listener for the
message
event. - Send a first message so SmartShape knows that the parent page is listening to its messages.
Here is an example:
function smartShapeMessageHandler(event) {
if (!event || !event.data || event.origin != 'https://smartshape.io.test')
return;
// Stop sending empty messages since we now receive messages from SmartShape.
window.clearInterval(timer);
timer = undefined;
let message = JSON.parse(event.data);
// Process the message coming from SmartShape.
}
// Listen to messages coming from SmartShape.
window.addEventListener("message", smartShapeMessageHandler, false);
let timer = window.setInterval(() => {
// Tell SmartShape the parent page is listening.
if (document.getElementById("smartshape"))
document.getElementById("smartshape").contentWindow.postMessage('[]', "https://localhost.smartshape.io.test");
}, 500);
SmartShape sends stringified JSON with the following structure:
[
"updateState",
[
{
"op": "replace",
"path": "/scene/focusedNode/id",
"value": "6581a4bb857abd8d44eda62a"
}
]
]
Where the second element of the root array is a list of JSON Patches applied to the state.
Any message that doesn't follow this structure is a legacy message that may be removed at any time.
3. Examples¶
3.1. Selecting Nodes¶
let message = {
"type": "patchState",
"data": [
{
"op": "replace",
"path": "/selectedNodes",
"value": {
"nodes": {
// ID of the Node(s) to select.
"6581a4bb857abd8d44eda62b": {},
"6581a4bb857abd8d44eda631": {},
},
// The timestamp must be specified.
"timestamp": Date.now()
}
},
]
};
document.getElementById("smartshape").contentWindow.postMessage(JSON.stringify(message), "https://smartshape.io.test");
3.2. Focusing a Node¶
let message = {
"type": "patchState",
"data": [
{
"op": "replace",
"path": "/scene/focusedNode/id",
"value": "6581a4bb857abd8d44eda631"
},
]
};
document.getElementById("smartshape").contentWindow.postMessage(JSON.stringify(message), "https://smartshape.io.test");
3.3. Listening to the Nodes selected in the 3D¶
function smartShapeMessageHandler(event) {
if (!event || !event.data || event.origin != 'https://smartshape.io.test')
return;
// Stop sending empty messages since we now receive messages from SmartShape.
window.clearInterval(timer);
timer = undefined;
const message = JSON.parse(event.data);
if (message[0] === 'updateState' && Array.isArray(message[1]) && message[1].length > 0 && message[1][0].path === '/selectedNodes') {
// Extract the ID of all the selected Nodes.
const selectedNodes = Object.keys(message[1][0].value.nodes);
if (selectedNodes.length > 0) {
console.log(`Selected node(s): ${selectedNodes}`);
} else {
console.log('Selection cleared.');
}
}
}