blob: 7b0924d39bf80ec65e776aba30ebc09ab68d98d9 [file] [log] [blame]
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
*
* Class: mxCellStatePreview
*
* Implements a live preview for moving cells.
*
* Constructor: mxCellStatePreview
*
* Constructs a move preview for the given graph.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph>.
*/
function mxCellStatePreview(graph)
{
this.deltas = new mxDictionary();
this.graph = graph;
};
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph>.
*/
mxCellStatePreview.prototype.graph = null;
/**
* Variable: deltas
*
* Reference to the enclosing <mxGraph>.
*/
mxCellStatePreview.prototype.deltas = null;
/**
* Variable: count
*
* Contains the number of entries in the map.
*/
mxCellStatePreview.prototype.count = 0;
/**
* Function: isEmpty
*
* Returns true if this contains no entries.
*/
mxCellStatePreview.prototype.isEmpty = function()
{
return this.count == 0;
};
/**
* Function: moveState
*/
mxCellStatePreview.prototype.moveState = function(state, dx, dy, add, includeEdges)
{
add = (add != null) ? add : true;
includeEdges = (includeEdges != null) ? includeEdges : true;
var delta = this.deltas.get(state.cell);
if (delta == null)
{
// Note: Deltas stores the point and the state since the key is a string.
delta = {point: new mxPoint(dx, dy), state: state};
this.deltas.put(state.cell, delta);
this.count++;
}
else if (add)
{
delta.point.x += dx;
delta.point.y += dy;
}
else
{
delta.point.x = dx;
delta.point.y = dy;
}
if (includeEdges)
{
this.addEdges(state);
}
return delta.point;
};
/**
* Function: show
*/
mxCellStatePreview.prototype.show = function(visitor)
{
this.deltas.visit(mxUtils.bind(this, function(key, delta)
{
this.translateState(delta.state, delta.point.x, delta.point.y);
}));
this.deltas.visit(mxUtils.bind(this, function(key, delta)
{
this.revalidateState(delta.state, delta.point.x, delta.point.y, visitor);
}));
};
/**
* Function: translateState
*/
mxCellStatePreview.prototype.translateState = function(state, dx, dy)
{
if (state != null)
{
var model = this.graph.getModel();
if (model.isVertex(state.cell))
{
state.view.updateCellState(state);
var geo = model.getGeometry(state.cell);
// Moves selection cells and non-relative vertices in
// the first phase so that edge terminal points will
// be updated in the second phase
if ((dx != 0 || dy != 0) && geo != null && (!geo.relative || this.deltas.get(state.cell) != null))
{
state.x += dx;
state.y += dy;
}
}
var childCount = model.getChildCount(state.cell);
for (var i = 0; i < childCount; i++)
{
this.translateState(state.view.getState(model.getChildAt(state.cell, i)), dx, dy);
}
}
};
/**
* Function: revalidateState
*/
mxCellStatePreview.prototype.revalidateState = function(state, dx, dy, visitor)
{
if (state != null)
{
var model = this.graph.getModel();
// Updates the edge terminal points and restores the
// (relative) positions of any (relative) children
if (model.isEdge(state.cell))
{
state.view.updateCellState(state);
}
var geo = this.graph.getCellGeometry(state.cell);
var pState = state.view.getState(model.getParent(state.cell));
// Moves selection vertices which are relative
if ((dx != 0 || dy != 0) && geo != null && geo.relative &&
model.isVertex(state.cell) && (pState == null ||
model.isVertex(pState.cell) || this.deltas.get(state.cell) != null))
{
state.x += dx;
state.y += dy;
}
this.graph.cellRenderer.redraw(state);
// Invokes the visitor on the given state
if (visitor != null)
{
visitor(state);
}
var childCount = model.getChildCount(state.cell);
for (var i = 0; i < childCount; i++)
{
this.revalidateState(this.graph.view.getState(model.getChildAt(state.cell, i)), dx, dy, visitor);
}
}
};
/**
* Function: addEdges
*/
mxCellStatePreview.prototype.addEdges = function(state)
{
var model = this.graph.getModel();
var edgeCount = model.getEdgeCount(state.cell);
for (var i = 0; i < edgeCount; i++)
{
var s = state.view.getState(model.getEdgeAt(state.cell, i));
if (s != null)
{
this.moveState(s, 0, 0);
}
}
};