Aller au contenu

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:

{
    "type": "patchState",
    "data": [
        ...
    ]
}

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.');
        }
    }
}

February 21, 2024 February 21, 2024