Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fit to screen on model update is unreliable #121

Open
tomvdbussche opened this issue Sep 18, 2019 · 4 comments
Open

Fit to screen on model update is unreliable #121

tomvdbussche opened this issue Sep 18, 2019 · 4 comments

Comments

@tomvdbussche
Copy link

Whenever the model is updated I want to execute the FitToScreenAction. Currently I do this on the server side by implementing IModelUpdateListener and dispatching a FitToScreenAction (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 the InitializeCanvasBoundsAction. Because the FitToScreenAction depends on the canvas bounds, whenever the client receives the FitToScreenAction before the InitializeCanvasBoundsAction is executed, the model does not get fit to the screen.

@spoenemann
Copy link
Contributor

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?

@tomvdbussche
Copy link
Author

tomvdbussche commented Sep 18, 2019

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

@spoenemann
Copy link
Contributor

I understand. We might use the blockUntil property on UpdateModelCommand to block following actions until the InitializeCanvasBoundsAction is dispatched.

@martinber
Copy link

martinber commented May 27, 2024

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());

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants