Custom Operators
Custom operators are JavaScript objects that implement the Communicator.Operator interface. To write an operator you derive from the Operator
base class and implement some of the methods related to the various events coming from the browser.
In the example below we define a simple operator that only responds to the onMouseDown() and onMouseUp() events:
class SampleOperator implements Communicator.Operator.Operator {
private _viewer: Communicator.WebViewer;
private _partId: Communicator.PartId;
public constructor(viewer: Communicator.WebViewer) {
this._viewer = viewer;
this._partId = null;
}
public onMouseDown(event: Communicator.Event.MouseInputEvent): void {
const pickConfig = new Communicator.PickConfig(Communicator.SelectionMask.All);
this._viewer.view.pickFromPoint(event.getPosition(), pickConfig).then((selection) => {
if (selection.getSelectionType() !== Communicator.SelectionType.None) {
this._partId = selection.getNodeId();
this._viewer.model.setNodesOpacity([this._partId], 0.5);
}
});
}
public onMouseUp(event: Communicator.Event.MouseInputEvent): void {
if (this._partId !== null) {
this._viewer.model.setNodesOpacity([this._partId], 1.0);
this._partId = null;
}
}
public onMouseMove(event: Communicator.Event.MouseInputEvent): void {}
public onMousewheel(event: Communicator.Event.MouseWheelInputEvent): void {}
public onTouchStart(event: Communicator.Event.TouchInputEvent): void {}
public onTouchMove(event: Communicator.Event.TouchInputEvent): void {}
public onTouchEnd(event: Communicator.Event.TouchInputEvent): void {}
public onKeyDown(event: Communicator.Event.KeyInputEvent): void {}
public onKeyUp(event: Communicator.Event.KeyInputEvent): void {}
public onDeactivate(): void {}
public onActivate(): void {}
public onViewOrientationChange(): void {}
public stopInteraction(): void {}
}
Every event handler receives an event object related to its type of event. For mouse events, an example would be the type of MouseInputEvent, for touch events, the type is TouchInputEvent. The event object has various member functions to retrieve the mouse location, button status, and other relevant information.
Operators can be as simple as the one above that turn an object transparent while the mouse is pressed, or they can be much more complex and have multiple stages like an operator that performs a measurement operation and then positions the resulting markup based on user input. It is up to you to decide how complex you want to make the interaction that is encapsulated by a single operator.
When using custom operators, you should await the call to the parent class’ function before returning from your implementation. This can be achieved either by adding await to the parent’s function call:
async onMouseMove(event) {
await super.onMouseMove(event);
}
Or by returning the result of the parent’s function call:
async onMouseDown(event) {
return super.onMouseDown(event);
}
For a list of all Event objects please see the API Reference Manual.
Registering an operator
Custom operators must be registered with the OperatorManager. Registering the operator makes it available but does not activate it.
const myOperator = new SampleOperator(hwv);
var myOperatorHandle = hwv.operatorManager.registerCustomOperator(myOperator);
Registering an operator returns an identifier which you can then use to activate the operator later. Each custom operator has a unique handle.
Activating an operator
There are two ways to activate a registered operator. The first one is to simply push it on the operator “stack”.
hwv.operatorManager.push(myOperatorHandle);
HOOPS Web Viewer has a stack of standard operators active by default, as described in the standard operators page.
When using the push function, your custom operator will be added to the end of the stack and be first in line to receive events. You can then “pop” it from the stack at any time with the OperatorManager.pop() function.
You can also “replace” an existing operator on the stack at a specific position with OperatorManager.set():
hwv.operatorManager.set(myOperatorHandle, 1);
In this case, the default select operator is replaced by your custom operator at position 1 in the stack. If you want to remove an operator from the stack without replacing it, you can call the OperatorManager.remove() function. Be aware that this function will modify the position of all operators above it in the stack.
If you prefer to start over and define your operator stack from scratch, you can use the OperatorManager.clear() function which completely empties the operator stack.
To retrieve a particular Operator
object (to call functions on it, change settings, etc.) you can use the OperatorManager.getOperator() function. There can only be one object of a given type on the operator stack at a time, so you only need to pass the relevant operator ID to this function.
Event propagation
All operator events, such as OnMouseUp()
and OnMouseDown()
are sequentially propagated to all operators on the stack starting with the operator highest on the stack. This is so that multiple operators can be active at the same time and effectively run in parallel. Because of this, an operator must be carefully designed to not interfere with the behavior of other operators or the application must ensure that the operator is the only one active.
If an operator handles an event of a given type it often needs to “consume” the event meaning it needs to stop it from propagating down to the operators lower in the stack. In the case of the NavCubeOperator, for example, this is because the operator might have determined that the NavCube element has been clicked on. In that case, it makes no sense to send the mouse messages also to the Orbit operator which would result in an unexpected camera movement. Another example might be an operator only “interested” mouse events but letting all other event types (e.g. keyboard events) pass through.
To consume an event, simply call setHandled(true) on the event object in the function that processes the event. If this function is called all the operators lower in the stack will not see the event but instead, receive a stopInteraction() event indicating that their current action (e.g. orbiting the camera, moving the cutting plane, etc) should be canceled. You should make sure that your custom operator also handles the stopInteraction() event.
For a more advanced Operator Example please consult the Advanced operator concepts section in the Building a basic application tutorial.
Please see the reference manual for more information on each operator category. Some of them will also be discussed throughout this Programming Guide.