Open tomvdbussche opened 5 years ago
Why is an InitializeCanvasBoundsAction triggered? That should happen only if the root element of the model is changed (different type or id). Is that the case in your application?
When the client is initialized, the model is requested from the server. It seems however that when the client receive a response from the server, the model if first set to the default empty model. Only after that it is set to the actual model received from the server.
This is what I get in the browser console (added some extra info):
GraphicsDiagramServer: sending "requestModel"
GraphicsDiagramServer: receiving "requestBounds"
ActionDispatcher: handle SetModelAction
CommandStack: Executing SetModelCommand
ActionDispatcher: Action is postponed due to block condition "requestBounds"
Viewer: rendering SModelRoot { id: "EMPTY", type: "NONE" }
ActionDispatcher: handle InitializeCanvasBoundsAction
CommandStack: Executing InitializeCanvasBoundsCommand
ActionDispatcher: handle "requestBounds"
CommandStack: Executing RequestBoundsCommand
Viewer: rendering hidden
Viewer: rendering SModelRoot { id: "EMPTY", type: "NONE" }
ActionDispatcher: handle ComputedBoundsAction
GraphicsDiagramServer: sending "computedBounds"
GraphicsDiagramServer: receiving "updateModel"
ActionDispatcher: handle "updateModel"
CommandStack: Executing UpdateModelCommand
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
ActionDispatcher: handle InitializeCanvasBoundsAction
CommandStack: Executing InitializeCanvasBoundsCommand
GraphicsDiagramServer: receiving "fit"
ActionDispatcher: handle "fit"
CommandStack: Executing FitToScreenCommand
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
ViewportAnimation: 64 fps
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
ActionDispatcher: handle InitializeCanvasBoundsAction
CommandStack: Executing InitializeCanvasBoundsCommand
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
ActionDispatcher: handle InitializeCanvasBoundsAction
CommandStack: Executing InitializeCanvasBoundsCommand
Viewer: rendering SGraph { id: "my-diagram", type: "graph:mydiagram" }
In this example the FitToScreen actually worked due to the InitializeCanvasBoundsAction before it. If the FitToScreen was received earlier it would not work
I understand. We might use the blockUntil
property on UpdateModelCommand
to block following actions until the InitializeCanvasBoundsAction
is dispatched.
In case someone is searching on Google how to fit the diagram to screen. Here I paste an extract of my code, where I add a 1s timeout due to this bug
import "reflect-metadata";
import { LocalModelSource, TYPES } from 'sprotty';
import { FitToScreenAction } from 'sprotty-protocol';
import { createContainer } from './di.config';
import { createGraph } from './model-source';
import * as package_json from '../package.json';
export default async function run() {
const data = await (await fetch(
`${BACKEND_URL}/diagram-data`,
{ headers: HEADERS },
)).json();
const container = createContainer("sprotty-container");
const modelSource = container.get<LocalModelSource>(TYPES.ModelSource);
modelSource.updateModel(createGraph(data));
// Sleep 1s due to a bug in Sprotty: https://github.com/eclipse-sprotty/sprotty/issues/121
await new Promise(r => setTimeout(r, 1000));
await modelSource.actionDispatcher.dispatch(FitToScreenAction.create([]));
}
document.addEventListener("DOMContentLoaded", () => run());
Whenever the model is updated I want to execute the
FitToScreenAction
. Currently I do this on the server side by implementingIModelUpdateListener
and dispatching aFitToScreenAction
(like in the flow example). This does seem to work sometimes, but often nothing happens.The issue seems to be caused by a race between the
FitToScreenAction
and theInitializeCanvasBoundsAction
. Because theFitToScreenAction
depends on the canvas bounds, whenever the client receives theFitToScreenAction
before theInitializeCanvasBoundsAction
is executed, the model does not get fit to the screen.