Graph
dia.Graph
is the model holding all cells (elements and links) of the diagram. It inherits from mvc.Model. The collection of all the cells is stored in the property cells
as an mvc.Collection.
The graph is a powerful data model behind all JointJS diagrams. It not only provides efficient storage for directed graphs, but also offers useful algorithms for traversing the graphs.
In order for JointJS to find the correct constructor for your cell, the graph
option cellNamespace
must be provided in its constructor function when a graph is instantiated. Built-in shapes are usually located in the shapes
namespace, so this is a common namespace to use. It's possible to add custom shapes to this namespace, or alternatively, you may like to use a different namespace completely.
For example, if joint.shapes
is provided as the value of cellNamespace
, and a cell is of type 'custom.Element'
, then the graph looks up the shapes.custom.Element
model when deserializing a graph from JSON format. If the graph is instantiated as e.g. const graph = new dia.Graph({}, { cellNamespace: myCustomNamespace })
, then the graph
will read the model definition from the myCustomNamespace.custom.Element
object instead. This option is often used in combination with the cellViewNamespace
option on the joint.dia.Paper object.
constructorβ
Methodsβ
addCell()β
graph.addCell(cell[, opt])
Add a new cell to the graph. If cell
is an array, all the cells in the array will be added to the graph. Any additional option or custom property provided in the options object will be accessible in the callback function of the graph add event.
If opt.dry
is set to true
, the graph reference is not stored on the cell
after it's added.
If opt.async
is set to false
, this ensures the cell
is rendered synchronously.
If opt.sort
is set to false
, the cell
will be added at the end of the collection.
const rect = new joint.shapes.standard.Rectangle({
position: { x: 100, y: 100 },
size: { width: 90, height: 30 },
attrs: { label: { text: 'my rectangle' } }
});
const rect2 = rect.clone();
const link = new joint.shapes.standard.Link({ source: { id: rect.id }, target: { id: rect2.id } });
const graph = new joint.dia.Graph({}, { cellNamespace: joint.shapes });
graph.addCell(rect).addCell(rect2).addCell(link);
addCells()β
graph.addCells(cells[, opt])
graph.addCells(cell, cell, ..[, opt])
Add new cells to the graph. This is just a convenience method that wraps the addCell method.
bfs()β
graph.bfs(element, iteratee [, opt])
Traverse the graph using the Breadth-first search algorithm starting at element
(note the element itself will be visited too). iteratee
is a function of the form function(element, distance) {}
that will be called with the currently visited element and distance of that element from the root element of the search (the element
passed to bfs()
). If iteratee
explicitely returns false
, the search stops.
The following image shows the order in which elements are traversed in the graph:
Note that the bfs()
algorithm is not only capable of traversing tree graphs but it can traverse any directed graph too.
It is smart enough not to traverse an element that was already visited.
If opt.inbound
is true
, reverse the search direction (it's like reversing all the link directions, i.e. swaping their source
and target
).
If opt.outbound
is true
, search follows the link directions. Calling bfs()
with opt.outbound
set to true
is the most common case (graph is traversed following the direction of links).
If none of opt.inbound
and opt.outbound
are used or both options are set to true
, the graph is traversed in both directions (very rare use case).
If opt.deep
is true
, the traversal takes into account embedded elements too. This option has the usual meaning as in other methods were deep
option is used. For example, in a hierarchy A (top level element), A1 (embedded in A), B (top level element), where A is not directly connected to B but its embedded element is (there is a link from A1 ----> B), bfs(A)
would not visit B but bfs(A, function() {}, { deep: true })
would.
clear()β
graph.clear([options])
Remove all the cells from the graph. options
object can optionally contain additional data that is passed over to the event listeners of the graph cells remove event.
cloneCells()β
graph.cloneCells(cells)
Clone all the cells (elements and/or links) from the cells
array and return an object that maps the original cell ID to the clone (i.e. an object of the form { [original cell ID]: [clone] }
). The reason why this object is returned instead of an array of clones is that it is very useful to know which object the clone was created for.
The number of clones returned equals cells.length
. This function does not simply clone all the cells but it also reconstructs all the source/target and parent/embed references within cells
. This is very useful. For example, for a graph A --- L ---> B
, cloneCells([A, L, B])
returns { A.id: A2, L.id: L2, B.id: B2 }
resulting in a graph A2 --- L2 ---> B2
, i.e. the source and target of the link L2
is changed to point to A2
and B2
(in contrast to just looping over cells
and calling cell.clone()
on each item).
cloneSubgraph()β
graph.cloneSubgraph(cells [, opt])
Clone the whole subgraph, including all the connected links whose source/target is in the subgraph. This is equivalent to calling graph.cloneCells(graph.getSubgraph(cells))
.
If opt.deep
is true
, take into account embedded cells of the subgraph cells.
Return an object of the form { [original cell ID]: [clone] }
.
dfs()β
graph.dfs(element, iteratee [, opt])
Traverse the graph using the Depth-first search algorithm starting at element
(note the element itself will be visited too). iterate
is a function of the form function(element, distance) {}
that will be called with the currently visited element and distance of that element from the root element of the search (the element
passed to dfs()
). If iteratee
explicitely returns false
, the search stops.
The following image shows the order in which elements are traversed in the graph:
Note that the dfs()
algorithm is not only capable of traversing tree graphs but it can traverse any directed graph too. It is smart enough not to traverse an element that was already visited.
If opt.inbound
is true
, reverse the search direction (it's like reversing all the link directions, i.e. swaping their source
and target
).
If opt.outbound
is true
, search follows the link directions. Calling dfs()
with opt.outbound
set to true
is the most common case (graph is traversed following the direction of links).
If none of opt.inbound
and opt.outbound
are used or both options are set to true
, the graph is traversed in both directions (very rare use case).
If opt.deep
is true
, the traversal takes into account embedded elements too. This option has the usual meaning as in other methods were deep
option is used. For example, in a hierarchy A (top level element), A1 (embedded in A), B (top level element), where A is not directly connected to B but its embedded element is (there is a link from A1 ----> B), dfs(A)
would not visit B but dfs(A, function() {}, { deep: true })
would.
disconnectLinks()β
graph.disconnectLinks(element)
Disconnect all the associated links with the element
.
findModelsFromPoint()β
graph.findModelsFromPoint(point)
Find elements (instance of joint.dia.Element
) under a certain point in the graph. point
is an object with x
and y
properties. Returns an array of elements whose bounding box contains point
. Note that there can be more then one element as elements might overlap.
findModelsInArea()β
graph.findModelsInArea(rect)
Find elements (instance of joint.dia.Element
) in a certain area in the graph. rect
is an object with x
, y
, width
and height
properties. Returns an array of elements whose bounding box top/left coordinate falls into the rect
rectangle.
findModelsUnderElement()β
graph.findModelsUnderElement(element [, opt])
Find all the elements (instances of joint.dia.Element
) that are located below element
. opt.searchBy
parameter optionally determines what it means for an element to be below another element. Possible values are 'bbox'
(default), 'center'
, 'origin'
, 'corner'
, 'topRight'
, and 'bottomLeft'
.
fromJSON()β
graph.fromJSON(jsonObject, [options])
Load a graph from a JSON object (not string). Used in conjunction with the graph.toJSON()
function.
The options
object may contain additional data that is passed over to graph change event listeners.
Note that this method does not expect a JSON string but rather an object in the JSON format. Use JSON.parse(jsonString)
if you need to convert a JSON string into the object form:
graph.fromJSON(JSON.parse(jsonString));
Example of storing stringified JSON objects:
var jsonString = JSON.stringify(graph.toJSON());
// ... send jsonString to the server
// store jsonString to localStorage or do whatever you want
// later on ...
graph.fromJSON(JSON.parse(jsonString));
Example of storing JSON objects directly:
var jsonObject = graph.toJSON();
// ... send jsonObject to the server
// store jsonObject (e.g. in a non-relational database)
// later on ...
graph.fromJSON(jsonObject)
getBBox()β
graph.getBBox()
Returns the bounding box (g.Rect) that surrounds all cells in the graph. It returns null
if the graph is empty.
var bbox = graph.getBBox().inflate(10);
getCell()β
graph.getCell(id)
Get a cell from the graph by its id
.
getCells()β
graph.getCells()
Return an array of all elements and links in the graph. The cells are sorted by their z
index (the smallest z
being first).
getCellsBBox()β
graph.getCellsBBox(cells[, opt])
Returns the bounding box (g.Rect) that surrounds all the given cells.
// Get the bounding box of all `el1` successors and their embeds
var bbox = graph.getCellsBBox(graph.getSuccessors(el1), { deep: true });
getCommonAncestor()β
graph.getCommonAncestor(...cells)
Return the common ancestor of all the cells passed as arguments. For example, if an element B
is embedded in an element A
and an element C
is also embedded in the element A
, graph.getCommonAncestor(B, C)
returns the element A
. This also works on an arbitrary deep hierarchy.
getConnectedLinks()β
graph.getConnectedLinks(element [, opt])
Get all links connected with element
.
If opt.inbound === true
, return only inbound connected links. Conversely, if opt.outbound === true
, return only outbound connected links. If both of these options are left undefined, or if both of them are set to true
, return both inbound and outbound links.
By default, this function returns only immediate (shallow) inbound and outbound links - no recursion. (Note that connections from element
to embedded child elements, and connections to element
from embedding parent elements count as shallow, too - they too are returned.)
If opt.deep === true
, return all outside links that connect with element
or any of its descendants (descendants meaning elements that are embedded or deeply embedded within element
). The inbound
and outbound
options can still be applied on top of this option.
Note that the specification of opt.deep
excludes links that connect two descendants of element
(enclosed links). If you do need to find all links connected with and/or enclosed within element
, you should use opt.deep === true
alongside an additional option: opt.includeEnclosed === true
.
If opt.indirect === true
, also return links that can only be considered connected to element
if we go against the flow of directed links at link-link connections.
Example use:
var links = graph.getConnectedLinks(element); // inbound and outbound
var links = graph.getConnectedLinks(element, { outbound: true });
var links = graph.getConnectedLinks(element, { deep: true }); // inbound and outbound
var links = graph.getConnectedLinks(element, { inbound: true, deep: true });
var links = graph.getConnectedLinks(element, { outbound: true, deep: true, includeEnclosed: true });
var links = graph.getConnectedLinks(element, { indirect: true });
getElements()β
graph.getElements()
Return an array of all elements in the graph. The elements are sorted by their z
index (the smallest z
being first).
getFirstCell()β
graph.getFirstCell()
Get the first cell (element or link) in the graph. The first cell is defined as the cell with the lowest z
property (the cell most in the back, see the Presentation section of joint.dia.Element).
getLastCell()β
graph.getLastCell()
Get the last cell (element or link) in the graph. The last cell is defined as the cell with the highest z
property (the cell most in the front, see the Presentation section of joint.dia.Element).
getLinks()β
graph.getLinks()
Return an array of all links in the graph. The links are sorted by their z
index (the smallest z
being first).
getNeighbors()β
graph.getNeighbors(element [, opt])
Get all the neighbors of element
in the graph. Neighbors are all the elements connected to element
via either an inbound or an outbound link.
Accepts several options, which may be provided inside an opt
object:
deep
- also return all the neighbors of all the elements embedded insideelement
.inbound
- return only inbound neighbors (neighbors connected with a link whosetarget
is theelement
).outbound
- return only outbound neighbors (neighbors connected with a link whosesource
is theelement
).indirect
- in addition to standard rules (includingdeep
/outbound
/inbound
modifications), also return the elements that can only be considered neighbors ofelement
if we go against the flow of directed links at link-link connections.
getPredecessors()β
graph.getPredecessors(element [, opt])
Return an array of all the predecessors of element
. By default, Depth-first search algorithm is used (important for the order of returned elements).
If opt.breadthFirst
is set to true
, use Breadth-first search algorithm instead.
If opt.deep
is set to true
, take into account embedded elements too (see dfs() for details).
getSinks()β
graph.getSinks()
Return an array of all the leafs of the graph. Time complexity: O(|V|)
.
getSources()β
graph.getSources()
Return an array of all the roots of the graph. Time complexity: O(|V|)
.
getSubgraph()β
graph.getSubgraph(cells [, opt])
Return an array of cells that result from finding elements/links that are connected to any of the cells in the cells
array. This function loops over cells
and if the current cell is a link, it collects its source/target elements; if it is an element, it collects its incoming and outgoing links if both the link ends (source/target) are in the cells
array. For example, for a single element, the result is that very same element. For two elements connected with a link: A --- L ---> B
, the result of getSubgraph([A, B])
is [A, L, B]
and the result of getSubgraph([L])
is also [A, L, B]
.
If opt.deep
is true
take into account all the embedded cells too when finding neighboring links/elements.
getSuccessors()β
graph.getSuccessors(element [, opt])
Return an array of all the successors of element
. By default, a Depth-first search algorithm is used (important for the order of returned elements).
If opt.breadthFirst
is set to true
, use a Breadth-first search algorithm instead.
Generally, getSuccessors
cares about the direction of the links. It follows links from their source to target only. The resulting array contains the elements that you visit if you follow the directed links. The links are simply navigated, and embedding is not considered.
In the following image, the successors of A
are C
and B
. Embedding is not taken into account.
If opt.deep
is set to true
, embedded elements are taken into account too (see dfs() for details). That means elements connected to any of the descendants are also successors.
In the following image, if { deep: false }
, the only successor of A
is D
. Embedding is not taken into account. If { deep: true }
, and B
is embedded in A
, that means the successors of A
are C
and D
.
isNeighbor()β
graph.isNeighbor(elementA, elementB [, opt])
Return true
if elementB
is a neighbor of elementA
. A neighbor of an element is another element connected to it via an inbound and/or outbound link.
Accepts several options, which may be provided inside an opt
object:
deep
- returntrue
also ifelementB
is a neighbor of an element embedded inelementA
.outbound
- returntrue
only ifelementB
is a succeeding neighbor ofelementA
. For example, ifelementB
is connected to a directed link behind the connection ofelementA
.inbound
- returntrue
only ifelementB
is a preceding neighborelementA
. For example, ifelementB
is connected to a directed link ahead of the connection ofelementA
.indirect
- in addition to standard rules (includingdeep
/outbound
/inbound
modifications), also returntrue
ifelementB
can only be considered a neighbor ofelementA
if we go against the flow of directed links at link-link connections.
isPredecessor()β
graph.isPredecessor(elementA, elementB)
Return true
if elementB
is a predecessor of elementA
.
isSink()β
graph.isSink(element)
Return true
if element
is a leaf, i.e. there is no link coming out of the element. Time complexity: O(1)
.
isSource()β
graph.isSource(element)
Return true
if element
is a root, i.e. there is no link that targets the element. Time complexity: O(1)
.
isSuccessor()β
graph.isSuccessor(elementA, elementB)
Return true
if elementB
is a successor of elementA
.
maxZIndex()β
graph.maxZIndex()
Get the highest Z value in the graph (the value of the cell on front).
minZIndex()β
graph.minZIndex()
Get the lowest Z value in the graph (the value of the cell on the back).
removeCells()β
graph.removeCells(cells[, opt])
graph.removeCells(cell, cell, ..[, opt])
Removes the given cells from the graph.
removeLinks()β
graph.removeLinks(element)
Remove all the associated links with the element
.
resetCells()β
graph.resetCells(cells[, opt])
graph.resetCells(cell, cell, ..[, opt])
Reset cells in the graph. Update all the cells in the graph in one bulk. This is a more efficient method of adding cells to the graph if you want to replace all the cells in one go. The options
object can optionally contain additional data that is passed over to the event listeners of the graph reset event.
search()β
graph.search(element, iteratee [, opt])
Traverse the graph starting at element
following links. This function is a wrapper around dfs() or bfs(). By default, it uses dfs()
. If opt.breadthFirst
is set to true
, bfs()
will be used instead.
toJSON()β
graph.toJSON()
Return an object representation of the graph, which can be used for persistence or serialization. Use the graph.fromJSON()
function to load a previously converted graph.
Note that this method does not return a JSON string but rather an object that can then be serialized to JSON with JSON.stringify(jsonObject)
:
var jsonString = JSON.stringify(graph.toJSON());
translate()β
graph.translate(tx, ty [, opt])
Translate all cells in the graph by tx
and ty
pixels. It uses the dia.Element.translate()
and dia.Link.translate()
methods internally.
Eventsβ
Graph triggers several events of its own that you can react on.
addβ
Triggered when a new cell is added to the graph.
graph.on('add', function(cell) {
alert('New cell with id ' + cell.id + ' added to the graph.')
})
changeβ
Generic event triggered for any change in the graph.
removeβ
Triggered when a cell is removed from the graph.
Graph JSONβ
The JointJS graph JSON representation has the following format:
{
cells: [// Array of cells (ie. links and elements).
{
id: '3d90f661-fe5f-45dc-a938-bca137691eeb',// Some randomly generated UUID.
type: 'basic.Rect',
attrs: {
'stroke': '#000'
},
position: {
x: 0,
y: 50
},
angle: 90,
size: {
width: 100,
height: 50
},
z: 2,
embeds: [
'0c6bf4f1-d5db-4058-9e85-f2d6c74a7a30',
'cdbfe073-b160-4e8f-a9a0-22853f29cc06'
],
parent: '31f348fe-f5c6-4438-964e-9fc9273c02cb'
// ... and some other, maybe custom, data properties
}
]
}