blob: ad66f548a7a69d447e75cd1123ce7ba80504c176 [file] [log] [blame]
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxPartitionLayout
*
* Extends <mxGraphLayout> for partitioning the parent cell vertically or
* horizontally by filling the complete area with the child cells. A horizontal
* layout partitions the height of the given parent whereas a a non-horizontal
* layout partitions the width. If the parent is a layer (that is, a child of
* the root node), then the current graph size is partitioned. The children do
* not need to be connected for this layout to work.
*
* Example:
*
* (code)
* var layout = new mxPartitionLayout(graph, true, 10, 20);
* layout.execute(graph.getDefaultParent());
* (end)
*
* Constructor: mxPartitionLayout
*
* Constructs a new stack layout layout for the specified graph,
* spacing, orientation and offset.
*/
function mxPartitionLayout(graph, horizontal, spacing, border)
{
mxGraphLayout.call(this, graph);
this.horizontal = (horizontal != null) ? horizontal : true;
this.spacing = spacing || 0;
this.border = border || 0;
};
/**
* Extends mxGraphLayout.
*/
mxPartitionLayout.prototype = new mxGraphLayout();
mxPartitionLayout.prototype.constructor = mxPartitionLayout;
/**
* Variable: horizontal
*
* Boolean indicating the direction in which the space is partitioned.
* Default is true.
*/
mxPartitionLayout.prototype.horizontal = null;
/**
* Variable: spacing
*
* Integer that specifies the absolute spacing in pixels between the
* children. Default is 0.
*/
mxPartitionLayout.prototype.spacing = null;
/**
* Variable: border
*
* Integer that specifies the absolute inset in pixels for the parent that
* contains the children. Default is 0.
*/
mxPartitionLayout.prototype.border = null;
/**
* Variable: resizeVertices
*
* Boolean that specifies if vertices should be resized. Default is true.
*/
mxPartitionLayout.prototype.resizeVertices = true;
/**
* Function: isHorizontal
*
* Returns <horizontal>.
*/
mxPartitionLayout.prototype.isHorizontal = function()
{
return this.horizontal;
};
/**
* Function: moveCell
*
* Implements <mxGraphLayout.moveCell>.
*/
mxPartitionLayout.prototype.moveCell = function(cell, x, y)
{
var model = this.graph.getModel();
var parent = model.getParent(cell);
if (cell != null &&
parent != null)
{
var i = 0;
var last = 0;
var childCount = model.getChildCount(parent);
// Finds index of the closest swimlane
// TODO: Take into account the orientation
for (i = 0; i < childCount; i++)
{
var child = model.getChildAt(parent, i);
var bounds = this.getVertexBounds(child);
if (bounds != null)
{
var tmp = bounds.x + bounds.width / 2;
if (last < x && tmp > x)
{
break;
}
last = tmp;
}
}
// Changes child order in parent
var idx = parent.getIndex(cell);
idx = Math.max(0, i - ((i > idx) ? 1 : 0));
model.add(parent, cell, idx);
}
};
/**
* Function: execute
*
* Implements <mxGraphLayout.execute>. All children where <isVertexIgnored>
* returns false and <isVertexMovable> returns true are modified.
*/
mxPartitionLayout.prototype.execute = function(parent)
{
var horizontal = this.isHorizontal();
var model = this.graph.getModel();
var pgeo = model.getGeometry(parent);
// Handles special case where the parent is either a layer with no
// geometry or the current root of the view in which case the size
// of the graph's container will be used.
if (this.graph.container != null &&
((pgeo == null &&
model.isLayer(parent)) ||
parent == this.graph.getView().currentRoot))
{
var width = this.graph.container.offsetWidth - 1;
var height = this.graph.container.offsetHeight - 1;
pgeo = new mxRectangle(0, 0, width, height);
}
if (pgeo != null)
{
var children = [];
var childCount = model.getChildCount(parent);
for (var i = 0; i < childCount; i++)
{
var child = model.getChildAt(parent, i);
if (!this.isVertexIgnored(child) &&
this.isVertexMovable(child))
{
children.push(child);
}
}
var n = children.length;
if (n > 0)
{
var x0 = this.border;
var y0 = this.border;
var other = (horizontal) ? pgeo.height : pgeo.width;
other -= 2 * this.border;
var size = (this.graph.isSwimlane(parent)) ?
this.graph.getStartSize(parent) :
new mxRectangle();
other -= (horizontal) ? size.height : size.width;
x0 = x0 + size.width;
y0 = y0 + size.height;
var tmp = this.border + (n - 1) * this.spacing;
var value = (horizontal) ?
((pgeo.width - x0 - tmp) / n) :
((pgeo.height - y0 - tmp) / n);
// Avoids negative values, that is values where the sum of the
// spacing plus the border is larger then the available space
if (value > 0)
{
model.beginUpdate();
try
{
for (var i = 0; i < n; i++)
{
var child = children[i];
var geo = model.getGeometry(child);
if (geo != null)
{
geo = geo.clone();
geo.x = x0;
geo.y = y0;
if (horizontal)
{
if (this.resizeVertices)
{
geo.width = value;
geo.height = other;
}
x0 += value + this.spacing;
}
else
{
if (this.resizeVertices)
{
geo.height = value;
geo.width = other;
}
y0 += value + this.spacing;
}
model.setGeometry(child, geo);
}
}
}
finally
{
model.endUpdate();
}
}
}
}
};