Embedded Diagram
Embed an interactive cutting layout visualisation on your website using a simple iframe. It displays the optimised cut layout for a given calculation result. It can also talk to the surrounding page via postMessage.
Point it at a result of ours by job ID (result), or at a copy of the result
JSON you host yourself (src, see Your own JSON).
Quick Start
Section titled “Quick Start”<!-- Replace the result value with your calculation job ID --><div id="smartcut-vis-message">Loading...</div>
<iframe id="smartcut-vis" src="https://cutlistevo.com/embed/?result=1733" allowtransparency="true" frameborder="0" height="0"></iframe>Set the src attribute dynamically using the jobId returned by the /v3/calculate API call:
const jobId = 1733 // returned by /v3/calculatedocument.getElementById('smartcut-vis').src = `https://cutlistevo.com/embed/?result=${jobId}`A live example is available at: https://cutlistevo.com/embed/?result=1733
A result stays available for 24 hours. Past that the diagram shows “no result”,
unless you kept the JSON and served it yourself, which is what src is for.
Parameters
Section titled “Parameters”Pass parameters as query string values on the iframe src URL.
| Parameter | Description |
|---|---|
result |
The calculation job ID to display. Required unless src is given |
src |
URL of a result JSON you host yourself, described in Your own JSON. Used in place of result |
dn |
Set to true to disable the stock navigation controls |
hs |
Set to true to hide the stock information header |
Your own JSON
Section titled “Your own JSON”Save the result JSON when you receive it, put it anywhere you can serve a file
from, whether that is S3, your own CDN or your app’s storage, then point the
embed at that URL with src instead of result:
const src = encodeURIComponent('https://cdn.example.com/jobs/1733.json')document.getElementById('smartcut-vis').src = `https://cutlistevo.com/embed/?src=${src}`URL-encode the value, so a query string of its own does not merge into the
embed’s. Every other parameter behaves exactly as it does for result, including
colours, navigation and postMessage.
This is worth doing when:
- the diagram has to outlive our copy, such as an order confirmation, an archived quote or a job sheet a customer opens weeks later
- the page must not depend on our API. With
srcthe iframe never calls us, so the layout still draws if our service is unreachable - the result never came from a job you can re-request, because you hold the JSON and not a job ID we can look up
Accepted JSON
Section titled “Accepted JSON”Either of the two result documents you can already obtain:
| Document | Where it comes from |
|---|---|
| V3 API result | the body of GET /v3/result?id=…, or the result delivered for POST /v3/calculate |
| Embed result | the body of GET /result/embedded?id=… |
V1/V2 API results are not accepted. They name sides x1/x2/y1/y2 and nest
parts under each stock, which is a different document rather than a renamed one.
Re-fetch the job through V3, or store the embed result.
Store the response body verbatim, with no re-shaping and no unwrapping. If your own
records wrap it ({ order, result }), keep the result at a URL of its own:
// when the calculation completes, keep a copyconst result = await fetch(`https://api.smartcut.dev/v3/result?id=${jobId}`, { headers: { Authorization: process.env.SMARTCUT_API_KEY } // raw key, no Bearer}).then((r) => r.json())
await putSomewherePublic(`jobs/${jobId}.json`, JSON.stringify(result))Requirements
Section titled “Requirements”- Serve the file over HTTPS from an absolute URL. An
httpURL is blocked as mixed content by the browser. - Send
Access-Control-Allow-Origin: https://cutlistevo.com(or*) with the file. The iframe fetches it directly, so without CORS the browser blocks it. - Keep the file publicly readable: the request is sent without credentials, so cookies and auth headers of yours play no part.
- Stay under 25 MB.
Diagnosing a failure
Section titled “Diagnosing a failure”The reason is posted to the surrounding page as an error message (see
iframe Messages) and logged to the iframe’s console:
| Message | Meaning |
|---|---|
src must be an absolute URL |
the value was relative, or not a URL |
src must be an http or https URL |
the value used another scheme (data:, file:, …) |
could not fetch the JSON at src |
the host did not answer, or CORS blocked the read |
src responded 404 |
the host answered, with that status |
src did not return valid JSON |
the body did not parse, often an error page |
src JSON must be a V3 API result … |
the JSON parsed but is not a result document |
Colours
Section titled “Colours”Customise the colour scheme using HEX values (without the # prefix).
| Parameter | Description |
|---|---|
pca |
Part colour A |
pcb |
Part colour B |
pch |
Part colour on hover |
pcs |
Part colour when selected |
sc |
Stock (board) background colour |
tc |
Text colour |
Example:
https://cutlistevo.com/embed/?result=1733&pca=BAD0F5&pcb=346AC9&pch=E09318&pcs=D35A5A&sc=EBEB58iframe Messages
Section titled “iframe Messages”Communicate with the embed using the browser’s postMessage API.
Messages from the iframe
Section titled “Messages from the iframe”Listen for these events on window:
| Type | Description |
|---|---|
resize |
The embed has resized. w and h carry the new dimensions in pixels. |
loaded |
The visualisation has loaded and a result was found. payload carries the stock IDs. |
noResult |
No result was found for the given job ID, or the JSON at src held no placed parts. |
error |
An error occurred. message carries the error text. |
partClick |
A part was clicked. message carries part data. |
Messages to the iframe
Section titled “Messages to the iframe”Send these events to the iframe using contentWindow.postMessage:
| Type | Fields | Description |
|---|---|---|
navigate |
stockID |
Navigate to a specific stock item by its ID (e.g. '1.0') |
- The embed must be hosted on a page served over HTTPS. It will not work on HTTP.
- The iframe height starts at
0. Theresizemessage sets it. - A result is kept for 24 hours. Beyond that, render it from your own JSON.
srcreplacesresult: give one or the other, andsrcwins if both are set.
Full Example
Section titled “Full Example”<div id="smartcut-vis-message">Loading...</div>
<iframe id="smartcut-vis" src="https://cutlistevo.com/embed/?result=1733" allowtransparency="true" frameborder="0" height="0"></iframe>The same iframe, reading JSON you host. Only the query parameter changes:
<iframe id="smartcut-vis" src="https://cutlistevo.com/embed/?src=https%3A%2F%2Fcdn.example.com%2Fjobs%2F1733.json" allowtransparency="true" frameborder="0" height="0"></iframe>JavaScript
Section titled “JavaScript”window.addEventListener('message', (e) => { if (!e.data) return if (e.data?.origin !== 'smartcut') return
switch (e.data.type) { case 'resize': document.getElementById('smartcut-vis').style.height = e.data.h + 'px' break case 'loaded': document.getElementById('smartcut-vis-message').style.display = 'none' document.getElementById('smartcut-vis').style.visibility = 'visible' break case 'noResult': document.getElementById('smartcut-vis-message').innerText = 'No result found' break case 'error': document.getElementById('smartcut-vis-message').innerText = e.data.message break case 'partClick': console.log(e.data.message) break }}, false)
// Navigate to a specific stock itemdocument.getElementById('smartcut-vis').contentWindow.postMessage( { type: 'navigate', stockID: '1.0' })#smartcut-vis,#smartcut-vis-message { width: 100%; max-width: 1000px;}
#smartcut-vis { background-color: rgba(255, 255, 255, 0.3); box-sizing: border-box; visibility: hidden;}Related
Section titled “Related”- API guide covers producing the layout this diagram renders.
- Hosted store is the ready-made alternative to embedding.
- WordPress plugin does the same thing without writing code.