cleanups, and started preferring for ... of loops over for (i=0; ... when feasible

development
mcyph 2021-06-07 21:10:38 +10:00
parent 9d2e144637
commit 29fff201da
4 changed files with 893 additions and 1247 deletions

View File

@ -155,7 +155,7 @@ class Graph extends EventSource {
/**
* Holds the {@link Model} that contains the cells to be displayed.
*/
model: Model | null = null;
model: Model;
/**
* Holds the {@link GraphView} that caches the {@link CellState}s for the cells.
@ -400,27 +400,6 @@ class Graph extends EventSource {
*/
constrainRelativeChildren: boolean = false;
/**
* Specifies if a parent should contain the child bounds after a resize of
* the child. This has precedence over {@link constrainChildren}.
* @default true
*/
extendParents: boolean = true;
/**
* Specifies if parents should be extended according to the {@link extendParents}
* switch if cells are added.
* @default true
*/
extendParentsOnAdd: boolean = true;
/**
* Specifies if parents should be extended according to the {@link extendParents}
* switch if cells are added.
* @default false (for backwards compatibility)
*/
extendParentsOnMove: boolean = false;
/**
* Specifies the return value for {@link isRecursiveResize}.
* @default false (for backwards compatibility)
@ -556,8 +535,8 @@ class Graph extends EventSource {
/**
* Creates and returns a new {@link GraphHandler} to be used in this graph.
*/
createGraphHandler(): mxGraphHandler {
return new mxGraphHandler(this);
createGraphHandler(): GraphHandler {
return new GraphHandler(this);
}
/**
@ -1236,150 +1215,6 @@ class Graph extends EventSource {
return this.maximumGraphBounds;
}
/**
* Returns the bounding box for the geometries of the vertices in the
* given array of cells. This can be used to find the graph bounds during
* a layout operation (ie. before the last endUpdate) as follows:
*
* ```javascript
* var cells = graph.getChildCells(graph.getDefaultParent(), true, true);
* var bounds = graph.getBoundingBoxFromGeometry(cells, true);
* ```
*
* This can then be used to move cells to the origin:
*
* ```javascript
* if (bounds.x < 0 || bounds.y < 0)
* {
* graph.moveCells(cells, -Math.min(bounds.x, 0), -Math.min(bounds.y, 0))
* }
* ```
*
* Or to translate the graph view:
*
* ```javascript
* if (bounds.x < 0 || bounds.y < 0)
* {
* graph.view.setTranslate(-Math.min(bounds.x, 0), -Math.min(bounds.y, 0));
* }
* ```
*
* @param cells Array of {@link Cell} whose bounds should be returned.
* @param includeEdges Specifies if edge bounds should be included by computing
* the bounding box for all points in geometry. Default is `false`.
*/
getBoundingBoxFromGeometry(
cells: CellArray,
includeEdges: boolean = false
): Rectangle | null {
includeEdges = includeEdges != null ? includeEdges : false;
let result = null;
let tmp: Rectangle | null = null;
for (const cell of cells) {
if (includeEdges || cell.isVertex()) {
// Computes the bounding box for the points in the geometry
const geo = cell.getGeometry();
if (geo != null) {
let bbox = null;
if (cell.isEdge()) {
const addPoint = (pt: Point | null) => {
if (pt != null) {
if (tmp == null) {
tmp = new Rectangle(pt.x, pt.y, 0, 0);
} else {
tmp.add(new Rectangle(pt.x, pt.y, 0, 0));
}
}
};
if (cell.getTerminal(true) == null) {
addPoint(geo.getTerminalPoint(true));
}
if (cell.getTerminal(false) == null) {
addPoint(geo.getTerminalPoint(false));
}
const pts = geo.points;
if (pts != null && pts.length > 0) {
tmp = new Rectangle(pts[0].x, pts[0].y, 0, 0);
for (let j = 1; j < pts.length; j++) {
addPoint(pts[j]);
}
}
bbox = tmp;
} else {
const parent = <Cell>cell.getParent();
if (geo.relative) {
if (
parent.isVertex() &&
parent !== this.view.currentRoot
) {
tmp = this.getBoundingBoxFromGeometry(new CellArray(parent), false);
if (tmp != null) {
bbox = new Rectangle(
geo.x * tmp.width,
geo.y * tmp.height,
geo.width,
geo.height
);
if (cells.indexOf(parent) >= 0) {
bbox.x += tmp.x;
bbox.y += tmp.y;
}
}
}
} else {
bbox = Rectangle.fromRectangle(geo);
if (parent.isVertex() && cells.indexOf(parent) >= 0) {
tmp = this.getBoundingBoxFromGeometry(new CellArray(parent), false);
if (tmp != null) {
bbox.x += tmp.x;
bbox.y += tmp.y;
}
}
}
if (bbox != null && geo.offset != null) {
bbox.x += geo.offset.x;
bbox.y += geo.offset.y;
}
const style = this.getCurrentCellStyle(cell);
if (bbox != null) {
const angle = getValue(style, 'rotation', 0);
if (angle !== 0) {
bbox = getBoundingBox(bbox, angle);
}
}
}
if (bbox != null) {
if (result == null) {
result = Rectangle.fromRectangle(bbox);
} else {
result.add(bbox);
}
}
}
}
}
return result;
}
/**
* Clears all cell states or the states for the hierarchy starting at the
* given cell and validates the graph. This fires a refresh event as the

File diff suppressed because it is too large Load Diff

View File

@ -129,6 +129,91 @@ class Edge {
return edge;
}
/**
* Function: splitEdge
*
* Splits the given edge by adding the newEdge between the previous source
* and the given cell and reconnecting the source of the given edge to the
* given cell. This method fires <mxEvent.SPLIT_EDGE> while the transaction
* is in progress. Returns the new edge that was inserted.
*
* Parameters:
*
* edge - <mxCell> that represents the edge to be splitted.
* cells - <mxCells> that represents the cells to insert into the edge.
* newEdge - <mxCell> that represents the edge to be inserted.
* dx - Optional integer that specifies the vector to move the cells.
* dy - Optional integer that specifies the vector to move the cells.
* x - Integer that specifies the x-coordinate of the drop location.
* y - Integer that specifies the y-coordinate of the drop location.
* parent - Optional parent to insert the cell. If null the parent of
* the edge is used.
*/
splitEdge(
edge: Cell,
cells: CellArray,
newEdge: Cell,
dx: number = 0,
dy: number = 0,
x: number,
y: number,
parent: Cell | null = null
) {
parent = parent != null ? parent : edge.getParent();
const source = edge.getTerminal(true);
this.graph.batchUpdate(() => {
if (newEdge == null) {
newEdge = <Cell>this.cloneCell(edge);
// Removes waypoints before/after new cell
const state = this.graph.view.getState(edge);
let geo = newEdge.getGeometry();
if (geo != null && geo.points != null && state != null) {
const t = this.graph.view.translate;
const s = this.graph.view.scale;
const idx = findNearestSegment(state, (dx + t.x) * s, (dy + t.y) * s);
geo.points = geo.points.slice(0, idx);
geo = <Geometry>edge.getGeometry();
if (geo != null && geo.points != null) {
geo = <Geometry>geo.clone();
geo.points = geo.points.slice(idx);
this.graph.model.setGeometry(edge, geo);
}
}
}
this.cellsMoved(cells, dx, dy, false, false);
this.cellsAdded(
cells,
parent,
parent ? parent.getChildCount() : 0,
null,
null,
true
);
this.cellsAdded(
new CellArray(newEdge),
parent,
parent ? parent.getChildCount() : 0,
source,
cells[0],
false
);
this.cellConnected(edge, cells[0], true);
this.graph.fireEvent(
new EventObject(
InternalEvent.SPLIT_EDGE,
{ edge, cells, newEdge, dx, dy }
)
);
});
return newEdge;
}
/**
* Adds a new edge into the given parent {@link Cell} using value as the user
@ -216,112 +301,6 @@ class Edge {
return this.addCell(edge, parent, index, source, target);
}
/*****************************************************************************
* Group: Cell cloning, insertion and removal
*****************************************************************************/
/**
* Function: splitEdge
*
* Splits the given edge by adding the newEdge between the previous source
* and the given cell and reconnecting the source of the given edge to the
* given cell. This method fires <mxEvent.SPLIT_EDGE> while the transaction
* is in progress. Returns the new edge that was inserted.
*
* Parameters:
*
* edge - <mxCell> that represents the edge to be splitted.
* cells - <mxCells> that represents the cells to insert into the edge.
* newEdge - <mxCell> that represents the edge to be inserted.
* dx - Optional integer that specifies the vector to move the cells.
* dy - Optional integer that specifies the vector to move the cells.
* x - Integer that specifies the x-coordinate of the drop location.
* y - Integer that specifies the y-coordinate of the drop location.
* parent - Optional parent to insert the cell. If null the parent of
* the edge is used.
*/
splitEdge(
edge: Cell,
cells: CellArray,
newEdge: Cell,
dx: number = 0,
dy: number = 0,
x: number,
y: number,
parent: Cell | null = null
) {
parent = parent != null ? parent : edge.getParent();
const source = edge.getTerminal(true);
this.getModel().beginUpdate();
try {
if (newEdge == null) {
newEdge = <Cell>this.cloneCell(edge);
// Removes waypoints before/after new cell
const state = this.getView().getState(edge);
let geo = newEdge.getGeometry();
if (geo != null && geo.points != null && state != null) {
const t = this.getView().translate;
const s = this.getView().scale;
const idx = findNearestSegment(
state,
(dx + t.x) * s,
(dy + t.y) * s
);
geo.points = geo.points.slice(0, idx);
geo = <Geometry>edge.getGeometry();
if (geo != null && geo.points != null) {
geo = <Geometry>geo.clone();
geo.points = geo.points.slice(idx);
this.getModel().setGeometry(edge, geo);
}
}
}
this.cellsMoved(cells, dx, dy, false, false);
this.cellsAdded(
cells,
parent,
parent ? parent.getChildCount() : 0,
null,
null,
true
);
this.cellsAdded(
new CellArray(newEdge),
parent,
parent ? parent.getChildCount() : 0,
source,
cells[0],
false
);
this.cellConnected(edge, cells[0], true);
this.fireEvent(
new EventObject(
InternalEvent.SPLIT_EDGE,
'edge',
edge,
'cells',
cells,
'newEdge',
newEdge,
'dx',
dx,
'dy',
dy
)
);
} finally {
this.getModel().endUpdate();
}
return newEdge;
}
/*****************************************************************************
* Group: Folding
*****************************************************************************/

View File

@ -33,9 +33,17 @@ class EventObject {
this.name = name;
this.properties = [];
for (let i = 0; i < args.length; i += 2) {
if (args[i + 1] != null) {
this.properties[args[i]] = args[i + 1];
if (!!args[0] && args[0].constructor === Object) {
// A literal object ({})
for (const [key, value] of Object.entries(args[0])) {
this.properties[key] = value;
}
} else {
// two-values [key, value, key, value, ...]
for (let i = 0; i < args.length; i += 2) {
if (args[i + 1] != null) {
this.properties[args[i]] = args[i + 1];
}
}
}
}
@ -45,7 +53,6 @@ class EventObject {
*
* Holds the name.
*/
// name: string;
name: string = '';
/**
@ -53,7 +60,6 @@ class EventObject {
*
* Holds the properties as an associative array.
*/
// properties: any[];
properties: any = null;
/**
@ -61,7 +67,6 @@ class EventObject {
*
* Holds the consumed state. Default is false.
*/
// consumed: boolean;
consumed: boolean = false;
/**
@ -69,7 +74,6 @@ class EventObject {
*
* Returns <name>.
*/
// getName(): string;
getName(): string {
return this.name;
}
@ -79,7 +83,6 @@ class EventObject {
*
* Returns <properties>.
*/
// getProperties(): any[];
getProperties(): any {
return this.properties;
}
@ -89,7 +92,6 @@ class EventObject {
*
* Returns the property for the given key.
*/
// getProperty(key: string): any;
getProperty(key: string): any {
return this.properties[key];
}
@ -99,7 +101,6 @@ class EventObject {
*
* Returns true if the event has been consumed.
*/
// isConsumed(): boolean;
isConsumed(): boolean {
return this.consumed;
}
@ -109,7 +110,6 @@ class EventObject {
*
* Consumes the event.
*/
// consume(): void;
consume(): void {
this.consumed = true;
}