Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/steady-idle-returns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@joint/router-avoid": patch
---

MainThreadProvider - fire `processed` (and so the RouterService `idle` event) after every incremental change, not only after a full sync, matching the Worker provider's behaviour
31 changes: 22 additions & 9 deletions packages/joint-router-avoid/src/providers/MainThreadProvider.mts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ export class MainThreadProvider extends Provider {
return this.avoidInstance;
}

/**
* Runs a routing pass over the pending avoid changes and announces its
* completion. Every processing path must go through here - `processed`
* drives the `RouterService`'s `idle` event, and the Worker provider
* fires it after every batch, so the incremental main-thread paths
* (not just {@link sync}) have to fire it too for parity.
*/
protected processTransaction(): void {
this.avoidRouter.processTransaction();
this.trigger('processed');
}

/**
* Creates or updates the avoid shape for a JointJS element.
*
Expand All @@ -81,7 +93,7 @@ export class MainThreadProvider extends Provider {
// Only update the position and size of the shape.
avoidRouter.moveShape(existingShapeRef, shapeRect);
if (process) {
avoidRouter.processTransaction();
this.processTransaction();
}
return;
}
Expand All @@ -103,7 +115,7 @@ export class MainThreadProvider extends Provider {
});

if (process) {
avoidRouter.processTransaction();
this.processTransaction();
}
}

Expand All @@ -121,7 +133,9 @@ export class MainThreadProvider extends Provider {
connector.sourceId === undefined || connector.sourcePinId === undefined ||
connector.targetId === undefined || connector.targetPinId === undefined
) {
this.deleteConnector(connector.id);
// Forward `process`: inside a batched sync() the deletion must not
// process (and announce) a transaction of its own mid-batch.
this.deleteConnector(connector.id, process);
return;
}

Expand All @@ -146,7 +160,7 @@ export class MainThreadProvider extends Provider {
if (existingConnRef) {
// It was already created, we just updated the endpoints.
if (process) {
this.avoidRouter.processTransaction();
this.processTransaction();
}
return;
}
Expand All @@ -161,7 +175,7 @@ export class MainThreadProvider extends Provider {
connRef.setCallback(this.onAvoidConnectorChanged, connRef);

if (process) {
this.avoidRouter.processTransaction();
this.processTransaction();
}

return;
Expand All @@ -180,7 +194,7 @@ export class MainThreadProvider extends Provider {
delete this.shapeRefs[shapeId];

if (process) {
this.avoidRouter.processTransaction();
this.processTransaction();
}
}

Expand All @@ -199,7 +213,7 @@ export class MainThreadProvider extends Provider {
delete this.linksByPointer[connRef.g];

if (process) {
this.avoidRouter.processTransaction();
this.processTransaction();
}
}

Expand Down Expand Up @@ -244,8 +258,7 @@ export class MainThreadProvider extends Provider {
shapes.forEach((shape) => this.setShape(shape, false));
connectors.forEach((connector) => this.setConnector(connector, false));

this.avoidRouter.processTransaction();
this.trigger('processed');
this.processTransaction();
}

/**
Expand Down
25 changes: 25 additions & 0 deletions packages/joint-router-avoid/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -654,3 +654,28 @@ QUnit.module('destroy()', () => {
assert.deepEqual(cancelledLinks, []);
});
});

QUnit.module('idle after incremental changes (main thread)', () => {
// `MainThreadProvider` routes synchronously, so `idle` (driven by the
// provider's `processed`) must fire during the originating graph change,
// not only after `start()`'s initial sync / `routeAll()`.
QUnit.test('an element move fires idle', async assert => {
const { routerService, source } = await initRouterWithLink({ x: 0, y: 0 }, { x: 300, y: 0 });

let idleCount = 0;
routerService.on('idle', () => idleCount++);

source.position(50, 50);
assert.equal(idleCount, 1, 'idle fired for the element move');
});

QUnit.test('a link removal fires idle', async assert => {
const { routerService, link } = await initRouterWithLink({ x: 0, y: 0 }, { x: 300, y: 0 });

let idleCount = 0;
routerService.on('idle', () => idleCount++);

link.remove();
assert.equal(idleCount, 1, 'idle fired for the link removal');
});
});