Using multiple views
HOOPS Web Viewer 2024.6.0 and above supports multiple views on a single Web Viewer canvas. Common use cases include front, side, and top views, although you are able to set whatever camera your application requires. The number of views is only limited by the capability of the execution environment.
These views can have their own camera, draw mode, lights, and more. In fact, anything that is modified using a call on the View
class will be unique to that view. All these views share a single Model
(as well as several other viewer concepts), so any change to the model will be reflected in all views. For example, if you’re viewing a model with two views and move a part, it will move in all views.
There is a new type of key, the ViewKey
which is an identifier unique to a view. The initial view has a key of 0
. You’re able to add and delete views as needed using functions added to the WebViewer
class. When creating a new view, you need only supply a HTMLElement
or a string containing the ID of the HTMLElement
to set up a new 3D view. Each view is only drawn when it needs to be, so if you’re rotating a camera in one view, the other views will not be drawn.
Once you have created your new view, it will have its own operator stack which allows you to customize interaction.
Important
A user can only create additional views after the ModelStructureReady
callback has been triggered. Additionally, the initial view cannot be deleted.
Let’s imagine we have a page with two HTMLElement
containers with IDs of “viewer1” and “viewer2”. To create a new view, simply call WebViewer.AddView
with the ID of the container:
<div id="viewer1" class="hwv-view">Initial view</div>
<div id="viewer2" class="hwv-view">New view</div>
<script type="module">
import * as Communicator from "./hoops-web-viewer.mjs";
// initial view
const hwv = new Communicator.WebViewer({
container: "viewer1",
enginePath: ".",
endpointUri: "my_model.scs"
});
hwv.start();
hwv.setCallbacks({
modelStructureReady: () => {
// new view
hwv.addView({
container: "viewer2"
});
}
});
</script>
The class="hwv-view"
is not mandatory - you can use your own styling and layout. In the screenshot below, notice the multiple cameras provide different views, but a selection in one view also selects the same geometry in the second view.
To remove a view, use WebViewer.removeView
.
A more complete example which shows views being created in response to events can be found at HC_INSTALL_DIR/web_viewer/examples/multi_view.html and its related script HC_INSTALL_DIR/web_viewer/examples/scripts/examples/multi_view.js. This example uses classes to encapsulate the variables and logic, which is recommended for production applications.
API changes related to this feature
Callbacks
Several callbacks now have an additional ViewKey
parameter if they happen in a particular view, for example, camera changes. This has been added as the last parameter, so it shouldn’t affect existing callbacks if the user is not interested in multi-view.
Camera
Projection matrices are partially based on the dimensions of the canvas, so an additional, optional View
parameter has been added to functions that get these matrices. This only affects the default view if it isn’t provided.
Events
Since input events can now potentially happen in a canvas that could differ from the default, they now take a ViewKey
argument to their constructors. This also applies to keyboard input since we might want to know what view has focus when we press a key.
Model
The Model
class is largely unaffected. However, CAD views and CAD configurations need to take place in a specific view. So a parameter has been added.
Selection
Since there are multiple cameras now, we need to know which view we’re picking from when we do a screen-based selection. Several selection functions have been changed this way, with an optional View
parameter at the end. This defaults to the default view if not specified.
Snapshots
SnapshotConfig
has a optional parameter for a ViewKey
. This is also able to be set at the end of the constructor.
View
Several managers have been moved from the WebViewer
to the View
class since they are more suited to individual views than they are the global viewer. These are OverlayManager
, FloorplanManager
, and OperatorManager
. Each view now has its own operator stack, managed by the OperatorManager
. Any functions called on the view affect only the view in the canvas they own. So setting lights in one view should do nothing for other views, for example.
WebViewer
As above, the viewer no longer directly manages the OverlayManager
, FloorplanManager
, or the OperatorManager
. These symbols still exist in the WebViewer
for compatibility, they simply point to the default view’s version of these objects. The WebViewer
also still has a view
field which is simply the default view. There are also new functions to addView
, removeView
, and getView
, and a new field views
which is an array of views.
CallbackMap
The following have an additional ViewKey parameter at the end:
+ camera
+ frameDrawn
+ overlayViewportSet
+ transitionBegin
+ transitionEnd
+ viewOrientation
Camera
The following have an additional optional View
parameter at the end:
+ getProjectionMatrix
+ getFullMatrix
Event.InputEvent
A constructor and a getter have been added:
+ constructor(viewKey: ViewKey)
+ get viewKey(): ViewKey
Additionally, the following child types are affected by this. They now take a ViewKey
as the last argument to their constructor:
KeyInputEvent
MouseInputEvent
MouseWheelInputEvent
TouchInputEvent
Model
activateCadView
takes an AbstractView
as its first parameter
activateDefaultCadView
takes an AbstractView
as its first parameter
activateCadConfiguration
takes an AbstractView
as its first parameter
activateDefaultCadConfiguration
takes an AbstractView
as its first parameter
SelectionManager
The following take an optional View
as their last parameter:
selectFromPoint
selectAllFromPoint
selectFromRay
selectAllFromRay
beginScreenSelectByArea
beginRayDrillSelection
SnapshotConfig
Now has a public ViewKey
field and in addition the view key can be specified at construction as the last optional parameter.
View
The View
class now has a OperatorManager
, FloorplanManager
, and OverlayManager
taken from the WebViewer
. The WebViewer
version of these symbols simply point to the managers for view 0
.
WebViewer
view
is now a get
which returns the default View
. The OverlayManager
, FloorplanManager
, or the OperatorManager
are all now just getters for those managers on the default view. New functions have been added to manage views: addView
, removeView
, and getView
. addView
must be supplied an HTMLElement
or string
with the ID of an HTMLElement
where the new view will be situated. removeView
takes a ViewKey
and removes the associated view. getView
takes a ViewKey
and returns the View
it belongs to.
Legacy Viewer
The legacy viewer (the pre-ESM viewer) shares an engine with the ESM viewer and thus the engine is aware of the concept of multi-views even though there should be no actual API changes. Everything that worked before should still work, any behavior that has changed due to multi-canvas is a bug.
Limitations
Cutting planes work, but if there are several views, capping will only be drawn in one of them after a cutting plane drag. An update to a view will be drawn with capping intact.
Some effects such as simple shadow and bloom might behave poorly on certain systems if your canvases are of different sizes.
Certain selections such as sphere or convex polyhedron selections will operate on the visibility state of the default view.