-
Notifications
You must be signed in to change notification settings - Fork 84
Client Server Protocol
This page describes the protocol between a sprotty client and its model source. A model source is configured by binding an implementation to TYPES.ModelSource
, e.g. LocalModelSource
for a client-only source or WebSocketDiagramServer
for a server connected via web socket. Both approaches use the same protocol, so we will assume a remote server for the rest of this page for simplicity.
The approach for computing model layouts has a strong influence on the client-server protocol, therefore we address this topic before going into more details on the protocol itself.
Both the client and the server may have their share in computing the layout. Usually the client is responsible for the micro layout, that is the positioning and size computation for labels and other elements that add visual information to composite elements such as nodes. The server, in turn, is responsible for the macro layout, that is the arrangement of the main model elements (e.g. nodes and edges) with the goal of optimizing visual clarity and readability. Macro layout computation depends on the results of micro layout computation, hence the client computes its layout before the server does. With the default settings, client layout is switched on and server layout is switched off.
In the client the layout approach is configured with the ViewerOptions
:
overrideViewerOptions(container, {
needsClientLayout: true,
needsServerLayout: false
});
Client-side layouts are selected with the layout
property of model elements that support this, such as SNode and SCompartment. hbox
, vbox
, and stack
are built-in layout types that can be used here. The layout is computed in two phases:
- A
RequestBoundsAction
is received and the model is rendered invisibly, e.g. by assigning its containing DOM element a width and height of zero. The locally used fonts and CSS styles are applied during this hidden rendering phase. The resulting size information is used to invoke the selected layouts, and the updated bounds are written into aComputedBoundsAction
. - The model source takes care of applying the bounds stored in the
ComputedBoundsAction
to the model, and then initiates the visible rendering of the updated model with aSetModelAction
orUpdateModelAction
.
On the server, the layout approach is configured on a DefaultDiagramServer
instance:
diagramServer.setNeedsClientLayout(true);
diagramServer.setNeedsServerLayout(false);
The server-side layout is configured with an implementation of ILayoutEngine
. Either bind it through dependency injection or set it directly on a DefaultDiagramServer
instance. For graph-like models the ElkLayoutEngine
can be used, which employs the Eclipse Layout Kernel (ELK).
If no client-side layout is necessary, the ILayoutEngine
can be invoked directly after a new model is available. Otherwise the two-phase process explained above must be initiated, first triggering a hidden rendering and then invoking the server-side layout with the updated bounds.
The primary purpose of the diagram server is to provide models. The protocol for setting or updating the model differs depending on how the layout is computed.
In the following, C → S denotes a message from the client to the server, and C ← S denotes a message from the server to the client.
In this scenario, the server needs to provide a model with complete layout information, so no further processing by the client is required.
- Client requests a model
- C → S: RequestModelAction
- C ← S: SetModelAction
- Server updates the model
- C ← S: UpdateModelAction
The server sends RequestBoundsAction
to the client instead of updating the model directly. The client does not forward the resulting ComputedBoundsAction
to the server because that would be an unnecessary round-trip. The updated bounds are applied locally in the client instead.
- Client requests a model
- C → S: RequestModelAction
- C ← S: RequestBoundsAction
- Server updates the model
- C ← S: RequestBoundsAction
Same as scenario B), but here the ComputedBoundsAction
is processed on the server so it can apply its own layout engine to the updated model.
- Client requests a model
- C → S: RequestModelAction
- C ← S: RequestBoundsAction
- C → S: ComputedBoundsAction
- C ← S: UpdateModelAction
- Server updates the model
- C ← S: RequestBoundsAction
- C → S: ComputedBoundsAction
- C ← S: UpdateModelAction
Usually popups are shown when the user hovers the mouse cursor over an element, and they are hidden when the cursor leaves the element. The server might also show and hide popups spontaneously by sending a SetPopupModelAction
. An existing popup is hidden by setting a new popup model with NONE
as root element type.
- Client requests a hover popup
- C → S: RequestPopupModelAction
- C ← S: SetPopupModelAction
- Server updates the popup spontaneously
- C ← S: SetPopupModelAction
Usually the selection is changed by the user by clicking on model elements. The server might also manipulate the selection spontaneously by sending a SelectAction
.
- Client notifies about changed selection
- C → S: SelectAction
- Server changes the selection spontaneously
- C ← S: SelectAction