feat: add GraphDataModel.batchUpdate method (#213)

The method already exists in the `Graph` class. It needs to be made
available in `GraphDataModel` as well, to simplify the transaction
syntax.
Start using it in some places to simplify the syntax and also use
`Graph.batchUpdate`.
development
Thomas Bouffard 2023-07-06 07:02:20 +02:00 committed by GitHub
parent 0c7a68bcc1
commit 992f3af63d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 63 additions and 100 deletions

View File

@ -329,8 +329,7 @@ export const setCellStyles = (
value: any
) => {
if (cells.length > 0) {
model.beginUpdate();
try {
model.batchUpdate(() => {
for (let i = 0; i < cells.length; i += 1) {
const cell = cells[i];
@ -341,9 +340,7 @@ export const setCellStyles = (
model.setStyle(cell, style);
}
}
} finally {
model.endUpdate();
}
});
}
};
@ -377,8 +374,7 @@ export const setCellStyleFlags = (
value: boolean
) => {
if (cells.length > 0) {
model.beginUpdate();
try {
model.batchUpdate(() => {
for (let i = 0; i < cells.length; i += 1) {
const cell = cells[i];
@ -387,9 +383,7 @@ export const setCellStyleFlags = (
model.setStyle(cell, style);
}
}
} finally {
model.endUpdate();
}
});
}
};
@ -397,7 +391,7 @@ export const setCellStyleFlags = (
* Sets or removes the given key from the specified style and returns the
* new style. If value is null then the flag is toggled.
*
* @param style String of the form [(stylename|key=value);].
* @param style The style of the Cell.
* @param key Key of the style to be changed.
* @param flag Integer for the bit to be changed.
* @param value Optional boolean value for the given flag.

View File

@ -484,20 +484,14 @@ class Graph extends EventSource {
getContainsValidationErrorsResource = () => this.containsValidationErrorsResource;
/**
* Shortcut for updating the model in a transaction.
* Updates the model in a transaction.
*
* @param fn the update to be performed in the transaction.
*
* @see {@link GraphDataModel.beginUpdate}
* @see {@link GraphDataModel.endUpdate}
* @see {@link GraphDataModel.batchUpdate}
*/
batchUpdate(fn: () => void) {
this.getDataModel().beginUpdate();
try {
fn();
} finally {
this.getDataModel().endUpdate();
}
this.getDataModel().batchUpdate(fn);
}
/**

View File

@ -956,6 +956,31 @@ export class GraphDataModel extends EventSource {
this.endUpdate();
}
/**
* Updates the model in a transaction.
* This is a shortcut to the usage of {@link beginUpdate} and the {@link endUpdate} methods.
*
* ```javascript
* const model = graph.getDataModel();
* const parent = graph.getDefaultParent();
* const index = model.getChildCount(parent);
* model.batchUpdate(() => {
* model.add(parent, v1, index);
* model.add(parent, v2, index+1);
* });
* ```
*
* @param fn the update to be performed in the transaction.
*/
batchUpdate(fn: () => void) {
this.beginUpdate();
try {
fn();
} finally {
this.endUpdate();
}
}
/**
* Increments the {@link updateLevel} by one. The event notification
* is queued until {@link updateLevel} reaches 0 by use of
@ -971,9 +996,9 @@ export class GraphDataModel extends EventSource {
* and {@link endUpdate} calls as shown here:
*
* ```javascript
* var model = graph.getDataModel();
* var parent = graph.getDefaultParent();
* var index = model.getChildCount(parent);
* const model = graph.getDataModel();
* const parent = graph.getDefaultParent();
* const index = model.getChildCount(parent);
* model.beginUpdate();
* try
* {

View File

@ -1727,11 +1727,9 @@ class EdgeHandler {
isClone: boolean,
me: InternalMouseEvent
) {
const model = this.graph.getDataModel();
const parent = edge.getParent();
model.beginUpdate();
try {
this.graph.batchUpdate(() => {
let constraint = this.constraintHandler.currentConstraint;
if (constraint == null) {
@ -1739,9 +1737,7 @@ class EdgeHandler {
}
this.graph.connectCell(edge, terminal, isSource, constraint);
} finally {
model.endUpdate();
}
});
return edge;
}
@ -1752,8 +1748,7 @@ class EdgeHandler {
changeTerminalPoint(edge: Cell, point: Point, isSource: boolean, clone: boolean) {
const model = this.graph.getDataModel();
model.beginUpdate();
try {
model.batchUpdate(() => {
if (clone) {
const parent = edge.getParent();
const terminal = edge.getTerminal(!isSource);
@ -1770,9 +1765,7 @@ class EdgeHandler {
model.setGeometry(edge, geo);
this.graph.connectCell(edge, null, isSource, new ConnectionConstraint(null));
}
} finally {
model.endUpdate();
}
});
return edge;
}
@ -1782,8 +1775,7 @@ class EdgeHandler {
*/
changePoints(edge: Cell, points: Point[], clone: boolean) {
const model = this.graph.getDataModel();
model.beginUpdate();
try {
model.batchUpdate(() => {
if (clone) {
const parent = edge.getParent();
const source = edge.getTerminal(true);
@ -1802,9 +1794,7 @@ class EdgeHandler {
model.setGeometry(edge, geo);
}
} finally {
model.endUpdate();
}
});
return edge;
}
@ -2194,7 +2184,7 @@ class EdgeHandler {
this.destroyBends(this.virtualBends);
this.virtualBends = this.createVirtualBends();
}
if (this.customHandles) {
this.destroyBends(this.customHandles);
this.customHandles = this.createCustomHandles();
@ -2272,7 +2262,7 @@ class EdgeHandler {
this.virtualBends = [];
}
if (this.customHandles){
if (this.customHandles) {
this.destroyBends(this.customHandles);
this.customHandles = [];
}

View File

@ -86,13 +86,9 @@ class CircleLayout extends GraphLayout {
* Implements {@link GraphLayout#execute}.
*/
execute(parent: Cell) {
const model = this.graph.getDataModel();
// Moves the vertices to build a circle. Makes sure the
// radius is large enough for the vertices to not
// overlap
model.beginUpdate();
this.graph.batchUpdate(() => {
// Gets all vertices inside the parent and finds
// the maximum dimension of the largest vertex

View File

@ -80,16 +80,11 @@ class CompositeLayout extends GraphLayout {
* single transaction.
*/
execute(parent: Cell): void {
const model = this.graph.getDataModel();
model.beginUpdate();
try {
this.graph.batchUpdate(() => {
for (let i = 0; i < this.layouts.length; i += 1) {
this.layouts[i].execute.apply(this.layouts[i], [parent]);
}
} finally {
model.endUpdate();
}
});
}
}

View File

@ -75,13 +75,10 @@ class EdgeLabelLayout extends GraphLayout {
* @param e edges
*/
placeLabels(v: CellState[], e: CellState[]): void {
const model = this.graph.getDataModel();
// Moves the vertices to build a circle. Makes sure the
// radius is large enough for the vertices to not
// overlap
model.beginUpdate();
try {
this.graph.batchUpdate(() => {
for (let i = 0; i < e.length; i += 1) {
const edge = e[i];
@ -95,9 +92,7 @@ class EdgeLabelLayout extends GraphLayout {
}
}
}
} finally {
model.endUpdate();
}
});
}
/**

View File

@ -170,7 +170,6 @@ class MxFastOrganicLayout extends GraphLayout {
* given parent where <isVertexIgnored> returns false.
*/
execute(parent: Cell) {
const model = this.graph.getDataModel();
this.vertexArray = [];
let cells = this.graph.getChildVertices(parent);
@ -230,8 +229,7 @@ class MxFastOrganicLayout extends GraphLayout {
// Moves cell location back to top-left from center locations used in
// algorithm, resetting the edge points is part of the transaction
model.beginUpdate();
try {
this.graph.batchUpdate(() => {
for (let i = 0; i < n; i += 1) {
this.dispX[i] = 0;
this.dispY[i] = 0;
@ -341,9 +339,7 @@ class MxFastOrganicLayout extends GraphLayout {
}
this.graph.moveCells(this.vertexArray, dx, dy);
} finally {
model.endUpdate();
}
});
}
/**

View File

@ -183,7 +183,6 @@ class HierarchicalLayout extends GraphLayout {
*/
execute(parent: Cell, roots: Cell[] | Cell | null = null): void {
this.parent = parent;
const { model } = this.graph;
this.edgesCache = new Dictionary();
this.edgeSourceTermCache = new Dictionary();
this.edgesTargetTermCache = new Dictionary();
@ -234,8 +233,8 @@ class HierarchicalLayout extends GraphLayout {
this.roots = rootsCopy;
}
model.beginUpdate();
try {
const { model } = this.graph;
model.batchUpdate(() => {
this.run(parent);
if (this.resizeParent && !parent.isCollapsed()) {
@ -253,9 +252,7 @@ class HierarchicalLayout extends GraphLayout {
model.setGeometry(parent, geo);
}
}
} finally {
model.endUpdate();
}
});
}
/**

View File

@ -361,8 +361,7 @@ class LayoutManager extends EventSource {
// Invokes the layouts while removing duplicates
const model = this.getGraph().getDataModel();
model.beginUpdate();
try {
model.batchUpdate(() => {
let last = null;
for (const cell of cells) {
@ -373,9 +372,7 @@ class LayoutManager extends EventSource {
}
this.fireEvent(new EventObject(InternalEvent.LAYOUT_CELLS, { cells }));
} finally {
model.endUpdate();
}
});
}
}

View File

@ -86,8 +86,7 @@ class ParallelEdgeLayout extends GraphLayout {
execute(parent: Cell, cells: Cell[] | null = null): void {
const lookup = this.findParallels(parent, cells);
this.graph.model.beginUpdate();
try {
this.graph.batchUpdate(() => {
for (const i in lookup) {
const parallels = lookup[i];
@ -95,9 +94,7 @@ class ParallelEdgeLayout extends GraphLayout {
this.layout(parallels);
}
}
} finally {
this.graph.model.endUpdate();
}
});
}
/**

View File

@ -207,18 +207,13 @@ class SwimlaneManager extends EventSource {
*/
cellsAdded(cells: Cell[]) {
if (cells.length > 0) {
const model = this.graph.getDataModel();
model.beginUpdate();
try {
this.graph.batchUpdate(() => {
for (const cell of cells) {
if (!this.isSwimlaneIgnored(cell)) {
this.swimlaneAdded(cell);
}
}
} finally {
model.endUpdate();
}
});
}
}
@ -260,10 +255,7 @@ class SwimlaneManager extends EventSource {
*/
cellsResized(cells: Cell[]) {
if (cells.length > 0) {
const model = this.getGraph().getDataModel();
model.beginUpdate();
try {
this.graph.batchUpdate(() => {
// Finds the top-level swimlanes and adds offsets
for (const cell of cells) {
if (!this.isSwimlaneIgnored(cell)) {
@ -291,9 +283,7 @@ class SwimlaneManager extends EventSource {
}
}
}
} finally {
model.endUpdate();
}
});
}
}
@ -307,8 +297,7 @@ class SwimlaneManager extends EventSource {
resizeSwimlane(swimlane: Cell, w: number, h: number, parentHorizontal: boolean) {
const model = this.graph.getDataModel();
model.beginUpdate();
try {
model.batchUpdate(() => {
const horizontal = this.isCellHorizontal(swimlane);
if (!this.isSwimlaneIgnored(swimlane)) {
@ -344,9 +333,7 @@ class SwimlaneManager extends EventSource {
const child = swimlane.getChildAt(i);
this.resizeSwimlane(child, w, h, horizontal);
}
} finally {
model.endUpdate();
}
});
}
/**