Node resize revert via middleware is ignored when releasing the mouse quickly #771
|
Hello, I've run into an issue with the library and I'm not sure whether it's caused by my implementation or by the library itself. Use caseI need to reset a node's size after a resize operation when certain conditions are not met. My approach is to use a middleware:
ProblemThe issue is that, when releasing the mouse button, the node is not always reverted, even though the middleware restores its original size. If I resize the node slowly and release the mouse, everything works as expected. However, if I resize it quickly and release the mouse immediately, the node keeps its new size instead of reverting. I'm not sure whether I'm doing something wrong or if this is a bug in the library, so I thought I'd ask here. I've created a StackBlitz playground that reproduces the issue: Thanks in advance for your help! |
Replies: 1 comment
|
Hello @logan-brd , thank you for the stackblitz demo, it made the problem easy to reproduce. This is a bug in the ngDiagram library: a size measured during the resize gesture can be applied after the gesture ends, overwriting the size your middleware sets. That is why the revert works when you resize slowly and pause before releasing the mouse button, but not when you release it while still moving. We already know how to fix it, and the fix will be included in the next ngDiagram version. We want to release it as soon as possible A few additional topics below. How you can achieve resize validationYour idea with middleware is correct. This is the shape we recommend. Note that today it still hits the race described above, so until the fix is released please use the workaround from the next section. Your implementation can be simplified with export class ResizeValidationMiddleware implements Middleware {
readonly name = "deviceResizeValidation";
execute(
context: MiddlewareContext,
next: (stateUpdate?: FlowStateUpdate) => Promise<FlowState>,
) {
const { modelActionTypes, actionStateManager, nodesMap } = context;
if (!modelActionTypes.includes("resizeNodeStop")) {
next();
return;
}
const resize = actionStateManager.resize;
const node = resize ? nodesMap.get(resize.resizingNode.id) : undefined;
if (!resize || !node) {
next();
return;
}
// insert validation logic here, `node.size` holds the size produced by the gesture
next({
nodesToUpdate: [
{
id: node.id,
size: { width: 150, height: 50 },
},
],
});
}
}Alternatively you could omit middleware and use the @Component({
selector: "app-root",
imports: [NgDiagramComponent],
providers: [provideNgDiagram()],
template: `
<ng-diagram [model]="model" (nodeResizeEnded)="nodeResizeEnded($event)" />
`,
styles: [":host { display: flex; height: 300px;}"],
})
export class App {
model = initializeModel({
nodes: [
{
id: "1",
position: { x: 100, y: 150 },
data: { label: "Node 1" },
size: { width: 600, height: 50 },
},
],
});
private readonly modelService = inject(NgDiagramModelService);
async nodeResizeEnded(event: NodeResizeEndedEvent) {
// insert validate logic here
this.modelService.updateNode(event.node.id, {
size: {
height: 50,
width: 100,
},
});
}
}This runs as a second model update after the resize is already committed, so it costs 2 rendering cycles and 2 model updates. The middleware does it in a single atomic update, so I woud say the middleware is preferable. Workaround until the fix is releasedThe easiest workaround is to temporarily use the @Component({
selector: "app-root",
imports: [NgDiagramComponent],
providers: [provideNgDiagram()],
template: `
<ng-diagram [model]="model" (nodeResizeEnded)="nodeResizeEnded($event)" />
`,
styles: [":host { display: flex; height: 300px;}"],
})
export class App {
model = initializeModel({
nodes: [
{
id: "1",
position: { x: 100, y: 150 },
data: { label: "Node 1" },
size: { width: 600, height: 50 },
},
],
});
private readonly modelService = inject(NgDiagramModelService);
async nodeResizeEnded(event: NodeResizeEndedEvent) {
// insert validate logic here
setTimeout(() => {
this.modelService.updateNode(event.node.id, {
size: {
height: 50,
width: 100,
},
});
}, 100);
}
}The workaround isn't ideal:
Further stepsYour case, resize validation beyound minSize, looks like a good candidate for a dedicated validation function in our config object. With that you wouldn't need a full middleware for this kind of rule. We will think about how it should fit our API and include it in a future release. Thank you very much for your report, it helps us make the library better ! |
Hello @logan-brd , thank you for the stackblitz demo, it made the problem easy to reproduce.
This is a bug in the ngDiagram library: a size measured during the resize gesture can be applied after the gesture ends, overwriting the size your middleware sets. That is why the revert works when you resize slowly and pause before releasing the mouse button, but not when you release it while still moving. We already know how to fix it, and the fix will be included in the next ngDiagram version. We want to release it as soon as possible
A few additional topics below.
How you can achieve resize validation
Your idea with middleware is correct. This is the shape we recommend. Note that today it stil…