Skip to main content
Version: 4.1

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:

graph BFS algorithm

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: dia.Cell[]): { [id: string]: dia.Cell }

The method clones the cells provided and returns an object that maps the original ids to the cloned cells. The cloned cells are not added to the graph.

For more information, see the util.cloneCells() method.

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:

graph DFS algorithm

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.

graph.disconnectLinks(element)

Disconnect all the associated links with the element.

findCellsAtPoint()​

graph.findCellsAtPoint(point: dia.Point, opt?: FindAtPointOptions): dia.Cell[]

Find all the cells (elements and links) at a certain point in the graph. point is an object with x and y properties.

Returns an array of cells whose bounding box contains point. Note that there can be more then one cell as cells might overlap.

If opt.strict is set to true, the point must lie inside the cell's bounding box (not on the border).

findCellsInArea()​

graph.findCellsInArea(rect: dia.BBox, opt?: FindInAreaOptions): dia.Cell[]

Find all the cells (elements and links) in a certain area in the graph. rect is an object with x, y, width and height properties.

Returns an array of cells whose bounding box intersects with rect. If opt.strict is set to true, the cell must be fully contained within the rect.

findCellsUnderElement()​

graph.findCellsUnderElement(element: dia.Element, opt?: FindUnderElementOptions): dia.Cell[]

Find all the cells (elements and links) positioned below the specified element.

The optional opt.searchBy parameter defines the criteria for what constitutes a cell being 'below' the element. Available options include 'bbox' (default), 'center', 'top-left', 'bottom-right', 'top-right', and 'bottom-left'.

findElementsAtPoint()​

graph.findElementsAtPoint(point: dia.Point, opt?: FindAtPointOptions): dia.Element[]

Find elements (instance of dia.Element) at 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.

If opt.strict is set to true, the point must lie inside the element's bounding box (not on the border).

findElementsInArea()​

graph.findElementsInArea(rect: dia.BBox, opt?: FindInAreaOptions): dia.Element[]

Find elements (instance of 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 intersects with rect. If opt.strict is set to true, the element must be fully contained within the rect.

findElementsUnderElement()​

graph.findElementsUnderElement(
element: dia.Element,
opt?: FindUnderElementOptions
): dia.Element[]

Find all the elements (instances of dia.Element) that are located below element. The elements that are embedded in the element are excluded from the result.

The optional opt.searchBy parameter defines the criteria for what constitutes an element being 'below' another. Available options include 'bbox' (default), 'center', 'top-left', 'bottom-right', 'top-right', and 'bottom-left'.

findLinksAtPoint()​

graph.findLinksAtPoint(point: dia.Point, opt?: FindAtPointOptions): dia.Link[]

Find links (instance of dia.Link) at a certain point in the graph. point is an object with x and y properties.

Returns an array of links whose bounding box contains point. Note that there can be more then one link as links might overlap.

If opt.strict is set to true, the point must lie inside the link's bounding box (not on the border).

note

The method uses the link.getBBox() method to determine the bounding box of the link. Meaning that the bounding box of the link does not match the visual representation of the link.

findLinksInArea()​

graph.findLinksInArea(rect: dia.BBox, opt?: FindInAreaOptions): dia.Link[]

Find links (instance of dia.Link) in a certain area in the graph. rect is an object with x, y, width and height properties.

Returns an array of links whose bounding box intersects with rect. If opt.strict is set to true, the link must be fully contained within the rect.

findLinksUnderElement()​

graph.findLinksUnderElement(
element: dia.Element,
opt?: FindUnderElementOptions
): dia.Link[]

Find all the links (instance of dia.Link) that are located below element. The links that are connected to the element are excluded from the result.

The optional opt.searchBy parameter defines the criteria for what constitutes a link being 'below' the element. Available options include 'bbox' (default), 'center', 'top-left', 'bottom-right', 'top-right', and 'bottom-left'.

findModelsFromPoint()​

graph.findModelsFromPoint(point)

(deprecated) - Use findElementsAtPoint instead.

Find elements (instance of 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)

(deprecated) - Use findElementsInArea instead.

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])

(deprecated) - Use findElementsUnderElement instead.

Find all the elements (instances of 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.

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).

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 inside element.
  • inbound - return only inbound neighbors (neighbors connected with a link whose target is the element).
  • outbound - return only outbound neighbors (neighbors connected with a link whose source is the element).
  • indirect - in addition to standard rules (including deep/outbound/inbound modifications), also return the elements that can only be considered neighbors of element 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.

getSuccessors diagram no embedding

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.

getSuccessors diagram with embedding

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 - return true also if elementB is a neighbor of an element embedded in elementA.
  • outbound - return true only if elementB is a succeeding neighbor of elementA. For example, if elementB is connected to a directed link behind the connection of elementA.
  • inbound - return true only if elementB is a preceding neighbor elementA. For example, if elementB is connected to a directed link ahead of the connection of elementA.
  • indirect - in addition to standard rules (including deep/outbound/inbound modifications), also return true if elementB can only be considered a neighbor of elementA 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.

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.

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([opt])

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());

This method accepts an optional opt object, the opt.cellAttributes accepts same options as the dia.Cell.toJSON() method, which will impact the result of the toJSON() method.

transferCellEmbeds()​

graph.transferCellEmbeds(sourceCell, targetCell [, opt]);

Transfer embedded cells of sourceCell to targetCell.

graph.transferCellConnectedLinks(sourceCell, targetCell [, opt]);

Transfer all the links connected to sourceCell to targetCell.

The accepted opt object includes the same options as the opt parameter in the getConnectedLinks() method, allowing you to specify which links are to be transferred.

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.

tip

In addition, all events triggered by Elements and Links are propagated to their containing Graph as well.

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.

Types​

FindAtPointOptions​

interface FindAtPointOptions {
strict?: boolean;
}

FindInAreaOptions​

interface FindInAreaOptions {
strict?: boolean;
}

FindUnderElementOptions​

interface FindUnderElementOptions extends FindInAreaOptions, FindAtPointOptions {
searchBy?: 'bbox' | 'top' | 'left' | 'bottom' | 'right' | 'center' |
'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
}

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
}
]
}