What to expect in part 1
This part is about the integration basics of BabylonJS and Angular. I will show you how you can use your existing knowledge of Angular and combine it with a graphics engine to create a compelling and modern user experience. You can find the performance-related aspects in part 2.
Article Series
- Part 1: Integration Basics ⬅
- Part 2: Performance Optimization
- 🇩🇪 Part 3: Architekturlösung: Demo und Integrationsbeispiele
Integration Demo, BabylonJS and Angular working together
Take a look at the demo below, this is what we will discuss here. More specific, I will demonstrate how to implement the first tab (unoptimized), the other versions are discussed in part 2.
A Primer on BabylonJS
BabylonJS is a 2D/3D engine for the web and is based on the WebGL standard. It is possible to create complex visualizations, configurator tools, or games that run blazingly fast and are easy to use.
In contrast to other engines like Unity or Unreal, content created with BabylonJS is written in JavaScript or TypeScript. This means that it runs natively in the browser and therefore we can enter, manipulate, and extend the graphic content generation at any time. This is key for an easy integration between any graphics engine and SPA frameworks.
Where to start
Angular is a well-known application framework and you surely know how to use it. However, you might not yet know the intrinsics and basics of BabylonJS. BabylonJS provides us with a number of concepts and API interfaces that we need to integrate with our Angular code. The most important objects in the API are Engine
and Scene
. A closer look will show that they are similar to Angular services and components, concept-wise.
Before we start, we have to make a few assumptions:
- The
Engine
resembles an Angular service - The
Engine
renders aScene
- A
Scene
corresponds to an Angular component - A
Scene
holds information about its state
An engine works by rapidly rendering the scene image by image, this is called the renderLoop
.
In the next paragraphs, I will demonstrate you my approach to integrate Angular and BabylonJS.
Providing the Engine as an Angular Service
As mentioned, the Engine
can be compared to a service. What we have to do is to manage the state and provide it to the engine.
We embed the Engine
by using an Angular service as our singleton and proxy to the Engine
.
// store the Engine
engine: Engine;
// the Engine will render into the Canvas element
start(canvas: ElementRef, scene: Scene) {
this.engine = new Engine(this.canvas, true);
// ... you can add content to the Scene
// ignore the change events from the Engine in the Angular ngZone
this.ngZone.runOutsideAngular( () => {
// start the render loop and therefore start the Engine
this.engine.runRenderLoop(() => scene.render())
});
}
Create the “engine” with some content and start the render loop.
The service holds the Engine
state, but we also need a way to manipulate the Scene
. Each Scene
could correspond to an Angular component.
The Scene Component
Using an Angular component, we integrate the Scene
perfectly in our existing architecture.
The component template must contain a Canvas
and a reference where the graphics will be rendered:
That reference will be selected by our component and is provided to the service.
// ...
@ViewChild('rCanvas', {static: true})
canvasRef: ElementRef;
private scene: Scene;
constructor(private readonly engineService: EngineService) {}
// ...
ngOnInit(): void {
// .. manipulate the scene
}
ngAfterViewInit(): void {
// start the Engine
// be aware that we have to setup the Scene before
this.engineService.start();
}
The scene component calling the created Angular EngineService to start the graphics engine
Notice: To be sure that the Canvas
element is available in the DOM, the Engine
service is started after the view has been initialized.
But even if we are now able to display things, there are no interactions possible, yet. How can these two separate systems interact?
Interaction between Angular and BabylonJS
Now that everything is set up, we can begin to implement interactions between our graphics framework and the business application framework.
As discussed, the Engine
renders the Scene
in a loop, and therefore, we can change the Scene
, and the Engine
will update the rendered image accordingly.
Creating interaction with the scene is as easy as subscribing to any event in Angular, in our case listening to changes of our configuration object. The renderLoop
will do the rest by updating the rendered scene on the next iteration.
this.preferences.config.subscribe(config => {
// update config
this.someConfig = config;
// change / update asteroids
this.updateElements();
});
The scene component, listening to configuration changes
The other way round from BabylonJS to Angular is also straightforward: We add an event listener to e.g. the Scene
we want to interact with and do something with the event we receive.
const jupyter = this.engineService.createObject('jupyter');
jupyter.actionManager = new ActionManager(this.engineService.scene);
jupyter.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnPickUpTrigger,
() => this.onJupyterClick.next());
Creating a Scene object and adding an action to it
The ActionManager
, ExecuteCodeAction
, and OnPickUpTrigger
objects are BabylonJS’s way to register an onClicked
listener that executes a function. In this case, we will pass on the request and increase a click counter.
As you can see, integrating BabylonJS into Angular is straightforward, interaction is as easy as calling a function.
Conclusion
- Re-use your existing Angular knowledge
- Integrating BabylonJS into Angular is straightforward, interaction is as easy as calling a function
- Find the full source code on GitHub
- View and try yourself, here is the demo on Stackblitz (caution: Stackblitz might got problems with Chrome’s new cookie policy)
At this point, we have integrated Angular and BabylonJS. However it is not performant yet. Take a look at the Stackblitz demo and select unoptimized to see the effect of our doing so far.
Wrap Up
That’s it! We successfully integrated the 2D/3D graphics engine BabylonJS in our business application written with Angular and Typescript.
In part 2, you will see where performance pitfalls are, how to find and avoid them. Subscribe to our monthly newsletter to not miss the next article.