Mon 21 Jul 22:43:21 CEST 2025
This commit is contained in:
parent
3c318c933d
commit
b46b11bb50
409
js/ui/mxgraph/src/js/view/mxLayoutManager.js
Normal file
409
js/ui/mxgraph/src/js/view/mxLayoutManager.js
Normal file
|
@ -0,0 +1,409 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2006-2015, JGraph Ltd
|
||||||
|
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Class: mxLayoutManager
|
||||||
|
*
|
||||||
|
* Implements a layout manager that runs a given layout after any changes to the graph:
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* (code)
|
||||||
|
* var layoutMgr = new mxLayoutManager(graph);
|
||||||
|
* layoutMgr.getLayout = function(cell)
|
||||||
|
* {
|
||||||
|
* return layout;
|
||||||
|
* };
|
||||||
|
* (end)
|
||||||
|
*
|
||||||
|
* Event: mxEvent.LAYOUT_CELLS
|
||||||
|
*
|
||||||
|
* Fires between begin- and endUpdate after all cells have been layouted in
|
||||||
|
* <layoutCells>. The <code>cells</code> property contains all cells that have
|
||||||
|
* been passed to <layoutCells>.
|
||||||
|
*
|
||||||
|
* Constructor: mxLayoutManager
|
||||||
|
*
|
||||||
|
* Constructs a new automatic layout for the given graph.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
*
|
||||||
|
* graph - Reference to the enclosing graph.
|
||||||
|
*/
|
||||||
|
function mxLayoutManager(graph)
|
||||||
|
{
|
||||||
|
// Executes the layout before the changes are dispatched
|
||||||
|
this.undoHandler = mxUtils.bind(this, function(sender, evt)
|
||||||
|
{
|
||||||
|
if (this.isEnabled())
|
||||||
|
{
|
||||||
|
this.beforeUndo(evt.getProperty('edit'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Notifies the layout of a move operation inside a parent
|
||||||
|
this.moveHandler = mxUtils.bind(this, function(sender, evt)
|
||||||
|
{
|
||||||
|
if (this.isEnabled())
|
||||||
|
{
|
||||||
|
this.cellsMoved(evt.getProperty('cells'), evt.getProperty('event'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setGraph(graph);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends mxEventSource.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype = new mxEventSource();
|
||||||
|
mxLayoutManager.prototype.constructor = mxLayoutManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable: graph
|
||||||
|
*
|
||||||
|
* Reference to the enclosing <mxGraph>.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.graph = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable: bubbling
|
||||||
|
*
|
||||||
|
* Specifies if the layout should bubble along
|
||||||
|
* the cell hierarchy. Default is true.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.bubbling = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable: enabled
|
||||||
|
*
|
||||||
|
* Specifies if event handling is enabled. Default is true.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.enabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable: updateHandler
|
||||||
|
*
|
||||||
|
* Holds the function that handles the endUpdate event.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.updateHandler = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable: moveHandler
|
||||||
|
*
|
||||||
|
* Holds the function that handles the move event.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.moveHandler = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: isEnabled
|
||||||
|
*
|
||||||
|
* Returns true if events are handled. This implementation
|
||||||
|
* returns <enabled>.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.isEnabled = function()
|
||||||
|
{
|
||||||
|
return this.enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: setEnabled
|
||||||
|
*
|
||||||
|
* Enables or disables event handling. This implementation
|
||||||
|
* updates <enabled>.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
*
|
||||||
|
* enabled - Boolean that specifies the new enabled state.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.setEnabled = function(enabled)
|
||||||
|
{
|
||||||
|
this.enabled = enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: isBubbling
|
||||||
|
*
|
||||||
|
* Returns true if a layout should bubble, that is, if the parent layout
|
||||||
|
* should be executed whenever a cell layout (layout of the children of
|
||||||
|
* a cell) has been executed. This implementation returns <bubbling>.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.isBubbling = function()
|
||||||
|
{
|
||||||
|
return this.bubbling;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: setBubbling
|
||||||
|
*
|
||||||
|
* Sets <bubbling>.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.setBubbling = function(value)
|
||||||
|
{
|
||||||
|
this.bubbling = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: getGraph
|
||||||
|
*
|
||||||
|
* Returns the graph that this layout operates on.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.getGraph = function()
|
||||||
|
{
|
||||||
|
return this.graph;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: setGraph
|
||||||
|
*
|
||||||
|
* Sets the graph that the layouts operate on.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.setGraph = function(graph)
|
||||||
|
{
|
||||||
|
if (this.graph != null)
|
||||||
|
{
|
||||||
|
var model = this.graph.getModel();
|
||||||
|
model.removeListener(this.undoHandler);
|
||||||
|
this.graph.removeListener(this.moveHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.graph = graph;
|
||||||
|
|
||||||
|
if (this.graph != null)
|
||||||
|
{
|
||||||
|
var model = this.graph.getModel();
|
||||||
|
model.addListener(mxEvent.BEFORE_UNDO, this.undoHandler);
|
||||||
|
this.graph.addListener(mxEvent.MOVE_CELLS, this.moveHandler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: getLayout
|
||||||
|
*
|
||||||
|
* Returns the layout to be executed for the given graph and parent.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.getLayout = function(parent)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: beforeUndo
|
||||||
|
*
|
||||||
|
* Called from the undoHandler.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
*
|
||||||
|
* cell - Array of <mxCells> that have been moved.
|
||||||
|
* evt - Mouse event that represents the mousedown.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.beforeUndo = function(undoableEdit)
|
||||||
|
{
|
||||||
|
var cells = this.getCellsForChanges(undoableEdit.changes);
|
||||||
|
var model = this.getGraph().getModel();
|
||||||
|
|
||||||
|
// Adds all descendants
|
||||||
|
var tmp = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < cells.length; i++)
|
||||||
|
{
|
||||||
|
tmp = tmp.concat(model.getDescendants(cells[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
cells = tmp;
|
||||||
|
|
||||||
|
// Adds all parent ancestors
|
||||||
|
if (this.isBubbling())
|
||||||
|
{
|
||||||
|
tmp = model.getParents(cells);
|
||||||
|
|
||||||
|
while (tmp.length > 0)
|
||||||
|
{
|
||||||
|
cells = cells.concat(tmp);
|
||||||
|
tmp = model.getParents(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.executeLayoutForCells(cells);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: executeLayout
|
||||||
|
*
|
||||||
|
* Executes the given layout on the given parent.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.executeLayoutForCells = function(cells)
|
||||||
|
{
|
||||||
|
// Adds reverse to this array to avoid duplicate execution of leafes
|
||||||
|
// Works like capture/bubble for events, first executes all layout
|
||||||
|
// from top to bottom and in reverse order and removes duplicates.
|
||||||
|
var sorted = mxUtils.sortCells(cells, true);
|
||||||
|
sorted = sorted.concat(sorted.slice().reverse());
|
||||||
|
this.layoutCells(sorted);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: cellsMoved
|
||||||
|
*
|
||||||
|
* Called from the moveHandler.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
*
|
||||||
|
* cell - Array of <mxCells> that have been moved.
|
||||||
|
* evt - Mouse event that represents the mousedown.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.cellsMoved = function(cells, evt)
|
||||||
|
{
|
||||||
|
if (cells != null && evt != null)
|
||||||
|
{
|
||||||
|
var point = mxUtils.convertPoint(this.getGraph().container,
|
||||||
|
mxEvent.getClientX(evt), mxEvent.getClientY(evt));
|
||||||
|
var model = this.getGraph().getModel();
|
||||||
|
|
||||||
|
// Checks if a layout exists to take care of the moving if the
|
||||||
|
// parent itself is not being moved
|
||||||
|
for (var i = 0; i < cells.length; i++)
|
||||||
|
{
|
||||||
|
var parent = model.getParent(cells[i]);
|
||||||
|
|
||||||
|
if (mxUtils.indexOf(cells, parent) < 0)
|
||||||
|
{
|
||||||
|
var layout = this.getLayout(parent);
|
||||||
|
|
||||||
|
if (layout != null)
|
||||||
|
{
|
||||||
|
layout.moveCell(cells[i], point.x, point.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: getCellsForEdit
|
||||||
|
*
|
||||||
|
* Returns the cells to be layouted for the given sequence of changes.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.getCellsForChanges = function(changes)
|
||||||
|
{
|
||||||
|
var dict = new mxDictionary();
|
||||||
|
var result = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < changes.length; i++)
|
||||||
|
{
|
||||||
|
var change = changes[i];
|
||||||
|
|
||||||
|
if (change instanceof mxRootChange)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var cells = this.getCellsForChange(change);
|
||||||
|
|
||||||
|
for (var j = 0; j < cells.length; j++)
|
||||||
|
{
|
||||||
|
if (cells[j] != null && !dict.get(cells[j]))
|
||||||
|
{
|
||||||
|
dict.put(cells[j], true);
|
||||||
|
result.push(cells[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: getCellsForChange
|
||||||
|
*
|
||||||
|
* Executes all layouts which have been scheduled during the
|
||||||
|
* changes.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.getCellsForChange = function(change)
|
||||||
|
{
|
||||||
|
var model = this.getGraph().getModel();
|
||||||
|
|
||||||
|
if (change instanceof mxChildChange)
|
||||||
|
{
|
||||||
|
return [change.child, change.previous, model.getParent(change.child)];
|
||||||
|
}
|
||||||
|
else if (change instanceof mxTerminalChange || change instanceof mxGeometryChange)
|
||||||
|
{
|
||||||
|
return [change.cell, model.getParent(change.cell)];
|
||||||
|
}
|
||||||
|
else if (change instanceof mxVisibleChange || change instanceof mxStyleChange)
|
||||||
|
{
|
||||||
|
return [change.cell];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: layoutCells
|
||||||
|
*
|
||||||
|
* Executes all layouts which have been scheduled during the
|
||||||
|
* changes.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.layoutCells = function(cells)
|
||||||
|
{
|
||||||
|
if (cells.length > 0)
|
||||||
|
{
|
||||||
|
// Invokes the layouts while removing duplicates
|
||||||
|
var model = this.getGraph().getModel();
|
||||||
|
|
||||||
|
model.beginUpdate();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var last = null;
|
||||||
|
|
||||||
|
for (var i = 0; i < cells.length; i++)
|
||||||
|
{
|
||||||
|
if (cells[i] != model.getRoot() && cells[i] != last)
|
||||||
|
{
|
||||||
|
if (this.executeLayout(this.getLayout(cells[i]), cells[i]))
|
||||||
|
{
|
||||||
|
last = cells[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fireEvent(new mxEventObject(mxEvent.LAYOUT_CELLS, 'cells', cells));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
model.endUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: executeLayout
|
||||||
|
*
|
||||||
|
* Executes the given layout on the given parent.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.executeLayout = function(layout, parent)
|
||||||
|
{
|
||||||
|
var result = false;
|
||||||
|
|
||||||
|
if (layout != null && parent != null)
|
||||||
|
{
|
||||||
|
layout.execute(parent);
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: destroy
|
||||||
|
*
|
||||||
|
* Removes all handlers from the <graph> and deletes the reference to it.
|
||||||
|
*/
|
||||||
|
mxLayoutManager.prototype.destroy = function()
|
||||||
|
{
|
||||||
|
this.setGraph(null);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user