Verge3D is a 3D viewer that can be used to bring your Blender, 3ds Max or Maya scene to life in the browser. For more information on how to use it, please refer to the Verge3D documentation.
Using the Elfsquad Verge3D blocks, you can easily create interactions between the Showroom and your 3D scene. An overview of the available blocks and other examples can be found on GitHub.
Plugins can be installed by unzipping the zip file inside Verge3D's puzzles/plugins directory. The default location for the plugins should be: %USERPROFILE%\verge3d_blender\puzzles\plugins.
The Elfsquad Verge3D plugin provides sample scenes for the Showroom. These can be found in the Examples directory.
If you would like to use this example scene you must setup the External application directory in the Verge3D App Manager:
This should add a new entry to your Verge3D App Manager: Parametric Models. This is a modified version of the original Parameteric Models sample scene, that interacts with the Showroom, using the newly added Elfsquad Verge3D blocks.
A block has been added to listen to configuration updates and update the configuration model accordingly:
Update requirement actions have been added to the UI buttons to tell the configurator to update the configuration model:
A JavasScript block has been added to trigger the On configuration update event when the scene is fully loaded:
In order to fully interact with the sample Verge3D scene, we need to setup a configuration model that has 3 features: Height, Thickness, and Corners. It is important to use the same names and codes as the sample model:
The first thing we want to do is provide the user with a selection of available configuration models. In order to achieve this we can use the featuremodels endpoint:
GET /api/2/featuremodels?include=RootFeature
It is important we include the RootFeature property as it will contain information such as the name, price and image for a particular configuration model.
Identifier of the configuration session. This id is used for updating configuration values and requesting a quotation.
FeatureModel
object
Object that represents the entire configuration model. This object should be used to build the configurator UI.
Values
object
Object that contains all values of the configuration. The key represents the identifier of a feature model node. The value represents the selected value for that particular node.
Conflicts
object
If a conflict occurs during the configuration process this object will be filled with conflicting nodes and solution options.
In order to update a value for a particular option we use the update endpoint:
PUT /api/2/configurations/{configurationId}?ignoreConflicts=true&compress=true
The ignoreConflicts parameter is optional. When this parameter is set to true the configurator will automatically resolve any conflicts that might occur.The compress parameter is also optional, but recommended. It will ensure only values will be returned that actually changed.
Now that we have the Products component, we should register it as the base route. In the app-routing-module.ts file add a route to the Products component
import{NgModule}from'@angular/core';import{Routes,RouterModule}from'@angular/router';import{ProductsComponent}from'./products/products.component';const routes:Routes=[{ path:'', component:ProductsComponent}// <-- Route to the Products component];@NgModule({ imports:[RouterModule.forRoot(routes)], exports:[RouterModule]})exportclassAppRoutingModule{}
The first step to creating our product overview is the retrieve a list of all available configuration models.
In the ngOnInit method of the products.component.ts file call the Elfskot.configurator.getConfigurationModels method
The Elfskot.configurator.getConfigurationModels method takes 2 parameters
The preferred language ISO
A callback function
The callback function provides a object, with different elements, that can be used to setup your product selection page. For now we will only be using the features.
Next we add HTML and CSS to the ProductsComponent.
In the products.component.html file add
<divclass="product-overview"><div*ngFor="let product of products"class="product-card"[routerLink]="['configure', product.featureModelId]"><img[src]="product.imageUrl"/><h3[innerHTML]="product.description"></h3></div></div>
In the products.component.css file add
.product-overview{display: flex;flex-direction: row;flex-wrap: wrap;}.product-card{box-shadow:01px3pxrgba(0,0,0,0.12),01px2pxrgba(0,0,0,0.24);transition: all 0.3scubic-bezier(.25,.8,.25,1);cursor: pointer;margin:12px;width:320px;}.product-card h3{padding:12px;}.product-card img{width:100%;height:auto;}.product-card:hover{box-shadow:03px6pxrgba(0,0,0,0.16),03px6pxrgba(0,0,0,0.23);}
If we were to run the Angular project now we would get the following result:
Now that we have a product selection page, we can proceed to build the actual configurator.
First add a ConfiguratorComponent
ng generate component Configurator
Register a configuration route in the app-routing.module.ts
import{NgModule}from'@angular/core';import{Routes,RouterModule}from'@angular/router';import{ProductsComponent}from'./products/products.component';import{ConfiguratorComponent}from'./configurator/configurator.component';const routes:Routes=[{ path:'', component:ProductsComponent},{ path:'configure/:id', component:ConfiguratorComponent}// <-- Route to the Configurator component];@NgModule({ imports:[RouterModule.forRoot(routes)], exports:[RouterModule]})exportclassAppRoutingModule{}
In the configure route we added a id parameter that will be used to hold the identifier of the selected configuration model in the product overview page.
The Elfskot.configurator.startNewConfiguration method takes 3 parameters
The identifier of the configuration model
A language iso
Callback method that takes the new configuration object
The resulting configuration object contains many different fields that can be used to construct the interface of your configurator. In this tutorial we will be mainly focused on the totalPrice and steps fields.
The steps field should be used to construct the user interface. The steps are structured as follows
Steps
* Title (optional)* Type (0 = Hotspots, 1 = 3D)* Features * Description * UnitPrice * TotalPrice * Type (0 = Optional, 1 = Mandatory, 2 = Alternative, 3 = Or) * Features (Children of the current feature, recursive) * .. * ...* ...
To listen to changes in the configuration session we can add a configurationUpdated event listener in the ngOnInit function
Because of the recursive nature of the Steps -> Features -> Features structure we will need to create a new Angular component to hold the options of the configurator.
Add a ConfiguratorOption component to the project
ng generate component ConfiguratorOption
The ConfiguratorOption component will take a Feature object as input and act on all the user interactions for this feature.
import{Component,OnInit,Input}from'@angular/core';declarevarElfskot;@Component({ selector:'app-configurator-option', templateUrl:'./configurator-option.component.html', styleUrls:['./configurator-option.component.css']})exportclassConfiguratorOptionComponentimplementsOnInit{ @Input('feature') feature;constructor(){}ngOnInit(){}toggle():void{let value =1;if(this.feature.isSelected){ value =0;}Elfskot.configurator.updateRequirement(this.feature.id, value);}}
The toggle function calls Elfskot.configurator.updateRequirement which takes 2 parameters
The identifier of the selected element
A value, which should be a number
In the configurator-option.component.html file we define a template that can act on the different types of features
Add the ConfiguratorOption component to the ConfiguratorComponent#
Now that we have the ConfiguratorOption component defined, we can add it to the configurator page.
In the configurator.component.html we create a loop that will iterate over the different steps of the configuration model and call the ConfiguratorOption component for each rootfeature in the step.
<div*ngIf="configuration"class="configurator-container"><h2[innerHTML]="configuration.root.description"></h2><ng-container*ngFor="let step of configuration.steps"><app-configurator-option*ngFor="let feature of step.features"[feature]="feature"></app-configurator-option></ng-container><h3>Total price <small>{{configuration.totalPriceExclVat}}</small></h3><buttonrouterLink="/checkout">Request quote</button></div>
If we were to open a configuration now it would look like this
The checkout.component.html file is divided in 2 sections: before the request is submitted and after the request is submitted
<h3*ngIf="configuration">Request quote <small>{{configuration.root.description}}</small></h3><div*ngIf="!isSubmitted"><form#checkoutForm="ngForm"(ngSubmit)="requestQuote(checkoutForm.value)"><fieldset><legend>Request quote</legend><label>First name <inputtype="text"name="firstName"ngModel/></label><label>Last name <inputtype="text"name="lastName"ngModel/></label><label>Company name <inputtype="text"name="companyName"ngModel/></label><label>Phone number <inputtype="text"name="phoneNumber"ngModel/></label><label>Email <inputtype="email"name="email"ngModel/></label><label>Street <inputtype="email"name="streetName"ngModel/></label><label>Postal code <inputtype="email"name="postalCode"ngModel/></label><inputtype="submit"value="Submit"/></fieldset></form></div><div*ngIf="isSubmitted"><h2>Thank you for your quotation request!</h2></div>