If you implemented your own eShop, or we do not provide an integration with your eCommerce platform of choice, this article is for you.
Vectary setup
1.1. Create a folder for the product models
This is an important part of any integration. Use the id of the folder to fetch and map your models to the products you have/will setup in the e-shop.
You can see the id when it is selected inside the Dashboard, directly in the URL after the string &folderId=.
1.2. Create the model of your product/s
In this case, we created an abstract design called Awesomeness. The name of your project needs to match the name of your product.
Here is the model you can clone directly into a new project in your workspace: https://www.vectary.com/p/5s8oStuOPjH9E2xrRVje3q
It features a Variant with 3 different objects, and each of the variants contains the same 3 materials. Make sure to link the materials if they are the same between each variant.
We can expose these through the Floating UI by adding a Materials and a Variants sub-objects.
Please note that the source of the MSController is the Object Switcher containing the variants.
The name of the project matches the name of the product.
The names of the objects and their materials match the options/variants that are setup for the product in the e-shop.
Custom site setup
2.1. Add the HTML
The first thing needed to connect the model to site are the UI elements that allow to configure the product in the eshop.
These tipically are select inputs with different options, but we are not limited to that, it can be anything, like a bunch of different buttons for each property/variant.
Make sure to have the control over those and keep them structured. Here is an example based on the model created from step 1.2:
Any structure can be used to fit a specific design, but that will change how the code needs to be written to link the Variants and Materials of the 3D model, to the Product properties in the UI.
2.2. Add the 3D Model and the API script
Once the structure matches the product and the 3d model, we can start linking them. First add the iframe with the model and the API script:
<iframe
id="vectary_embed"
src="<https://app.vectary.com/p/{shared_model_id}>"
frameborder="0"
width="100%"
height="100%">
</iframe>
<script type="module">
import { VctrModelApi } from "<https://app.vectary.com/studio-lite/scripts/api.js>";
var modelApi = new VctrModelApi("vectary_embed");
await modelApi.init();
// Your code will go here
</script>
Please note:
You need to fill in {shared_model_id} with the id of the model you want to load at the start.
Feel free to change the iframe id to something else, but remember to also change it in the initialization of the VctrModelApi.
2.3. Add the custom code
At a very high level we want to listen to changes from the 3D model, and apply those into the UI of our eshop, and vice-versa.
We will be writing the code following the first structure from 2.1.:
listenToChangesFromModel will make use of our ApiEvents.CONFIGURATOR_STATE_CHANGE event listener:
async listenToChangesFromModel() {
// Takes care of applying the change of option to the select
const selectAndDispatchChange = (option: HTMLOptionElement) => {
if (option) {
option.selected = true;
const ev = new CustomEvent('change');
select.dispatchEvent(ev);
}
}
// Iterates through the current 3D state and Ui elements to find a match
const changeUiFromModel = (configs: ConfigurationState[]) => {
// Retrieve the elements containing the product options and iterate
const selects = document.querySelectorAll("select");
this.selects.forEach(select => {
// Check if there are any options matching the current config
configs.forEach(config => {
// Config can be either a Material or a Variant
const config_active_value = config.active_material ?
config.active_material : config.active_object ?
config.active_object : null;
if (config_active_value) {
const optionToSelect = Array.from(select.options)
.find(option => option.value === config_active_value);
// Change the value and dispatch
selectAndDispatchChange(optionToSelect);
}
});
});
}
// Initialize the event listener for the 3D model and attatch the cb()
await this.modelApi.addEventListener(
ApiEvents.CONFIGURATOR_STATE_CHANGE, // "configurator_state_change"
(configs: ConfigurationState[]) => changeUiFromModel(configs)
);
}
listenToChangesFromUI() will make use of our getConfigurationState() and setConfigurationState(state: Array<ConfigurationState>) methods:
async listenToChangesFromUI() {
// Iterates through the current UI and 3D configurator to construct a state to pass onto the 3d model
const eventChangeHandler = async (ev: Event) => {
if (!ev.target) return;
// First loop focusing on the Variants, since the following Material options need to affect these
for (const select of this.selects) {
const currentConfigArray = await this.modelApi.getConfigurationState();
for (const config of currentConfigArray) {
// Check for Variant
if (config.active_object) {
// Check if the current select has this Variant
const hasOption = Array.from(select.options)
.find(option => option.value === config.active_object);
if (hasOption) {
// Check which one is the current selected
const selectedOption = Array.from(select.options)
.find(option => option.value === select.value);
if (selectedOption) {
// Construct the sate for the current selected option
const newVariantConfig = {
variant: config.variant,
active_object: selectedOption.value
}
// Set the state
await this.modelApi.setConfigurationState([newVariantConfig]);
}
}
}
}
}
// Second loop focusing on the Materials
for (const select of this.selects) {
const currentConfigArray = await this.modelApi.getConfigurationState();
for (const config of currentConfigArray) {
// Check for Material
if (config.active_material) {
// Check if the current select has this Material
const hasOption = Array.from(select.options)
.find(option => option.innerText === config.active_material);
if (hasOption) {
// Check which one is the current selected
const selectedOption = Array.from(select.options)
.find(option => option.value === select.value);
if (selectedOption) {
// Construct the sate for the current selected option
const newMaterialConfig = {
object: config.object,
active_material: selectedOption.value
}
// Set the state
await this.modelApi.setConfigurationState([newMaterialConfig]);
}
}
}
}
}
}
// Initialize the event listener for the selects
this.selects.forEach(select => {
select.removeEventListener("change", eventChangeHandler);
select.addEventListener("change", eventChangeHandler);
});
}
2.4. All together
We will add a CustomIntegration class to make things a bit more encapsulated.
Remember that this example is for when you are using select. You will need to adapt the code to retrieve the information from whatever other HTML structure you are using in your site.
PDF Generation
At some point, you may want your clients to be able to download a PDF of the current product’s configuration. Here’s an example on how you could start approaching such thing using the popular https://github.com/parallax/jsPDF library: