Data Binding

The Diagram can load external tree-like and graph structures. The supported data structures are listed below.

  • Node and Edge Arrays: the information about nodes is maintained separately from the information about edges.
  • Linear Array: nodes are maintained in a linear data structure and are connected by Key - Parent Key reference.
  • Hierarchical Array: nodes are maintained in hierarchical data structure.

When you bind a Diagram UI component to a data source, you should specify properties that allow the UI component to create the diagram structure. The supported data structures differ in required properties.

Required Properties Node and Edge Arrays Linear Array Hierarchical Array
nodes.keyExpr
edges.keyExpr
nodes.parentKeyExpr
nodes.itemsExpr

Two-Way Data Binding

View Demo

The Diagram component updates the bound data source and reloads the diagram content each time a user changes diagram data by the UI. If you modify the data source directly (beyond the Diagram), use push services to notify the component about data modifications. In this case, the Diagram gets notifications about data source changes and reloads diagram content.

Handle the requestLayoutUpdate event to make the Diagram recalculate and update the diagram layout each time data is reloaded.

If you use push services to modify data source data and specify item key values (IDs in a data source) manually, subscribe to the onInserting data source event to assign these values. Otherwise, the Diagram generates GUID key values for items that are added from the toolbox, pasted, cloned, or returned after being removed (by undo and redo operations).

We recommend that you do not set the reshapeOnPush property to true in the Diagram data source as it interferes with many of the diagram functions: Selection, History, Document Focus, etc.

Node and Edge Arrays

View Demo

Use the nodes.dataSource and edges.dataSource properties to bind the Diagram UI component to plain lists of nodes and edges.

Specify the following required properties: nodes.keyExpr, edges.keyExpr.

Do not specify the parentKeyExpr and itemsExpr properties, because they are a part of another binding mode.

During the binding process, the UI component creates a shape for every bound node and a connector for every bound edge. To attach a start or end of a connector to a shape, use the edges.fromExpr and edges.toExpr properties. These expressions should return keys of attached nodes.

index.js
data.js
    $(function() {
        $("#diagram").dxDiagram({
            nodes: {
                dataSource: new DevExpress.data.ArrayStore({
                    key: "this",
                    data: orgItems
                }),
                keyExpr: "id",
                textExpr: "text",
            },
            edges: {
                dataSource: new DevExpress.data.ArrayStore({
                    key: "this",
                    data: orgLinks
                }),
                keyExpr: "id",
                fromExpr: "from",
                toExpr: "to"
            },
        });
    });
    var orgItems = [{  
        "id":"101",
        "text":"Development",
    },{  
        "id":"102",
        "text":"Javascript\nTeam",
    },{  
        "id":"103",
        "text":"ASP.NET\nTeam",
    }];

    var orgLinks = [{  
        "id":"121",
        "from":"101",
        "to":"102",
    },{  
        "id":"122",
        "from":"101",
        "to":"103",
    }];

Diagram - Node and Edge Arrays

Linear Array

View Demo

Use the nodes.dataSource property to bind the UI component to a list of nodes where each record specifies a node's key value and includes a parent node's key value reference.

Specify the following required properties: nodes.keyExpr, nodes.parentKeyExpr.

Do not specify the nodes.itemsExpr and edges properties because they are a part of another binding mode.

During the binding process, the UI component creates a shape for every bound node and a connector between every pair of nodes linked by the Key - Parent Key reference. Note that edges are not maintained as entities in a data source, thus a detached connector disappears after rebinding.

index.js
data.js
    $(function() {
        $("#diagram").dxDiagram({
            nodes: {
                dataSource: new DevExpress.data.ArrayStore({
                    key: "this",
                    data: employees
                }),
                keyExpr: "ID",
                parentKeyExpr: "Head_ID",            
                textExpr: "Title",
                heightExpr: function() {return 0.4} 
            },
        });
    });
    var employees = [{
        "ID": 3,
        "Full_Name": "Arthur Miller",
        "Title": "CTO",
    }, {
        "ID": 6,
        "Head_ID": 3,
        "Full_Name": "Brett Wade",
        "Title": "IT Manager",
    }, {
        "ID": 9,
        "Head_ID": 3,
        "Full_Name": "Barb Banks",
        "Title": "Support Manager",
    }, {
        "ID": 18,
        "Head_ID": 9,
        "Full_Name": "James Anderson",
        "Title": "Support Assistant",
    }, {
        "ID": 21,
        "Head_ID": 6,
        "Full_Name": "Taylor Riley",
        "Title": "Network Admin",
    }, {
        "ID": 23,
        "Head_ID": 6,
        "Full_Name": "Wally Hobbs",
        "Title": "Programmer",
    }, {
        "ID": 24,
        "Head_ID": 6,
        "Full_Name": "Brad Jameson",
        "Title": "Programmer",
    }];

Diagram - Node and Edge Arrays

Hierarchical Array

View Demo

Use the nodes.dataSource property to bind the UI component to a hierarchical object.

Specify the following required properties: nodes.keyExpr, nodes.itemsExpr.

Do not specify the nodes.parentKeyExpr and edges properties because they are a part of another binding mode.

During the binding process, the UI component creates a shape for every bound node and all connectors that are between a node and its children. Note that the edges are not maintained as entities in a data source, thus the detached connector disappears after it is rebound.

index.js
data.js
    $(function() {
        $("#diagram").dxDiagram({
            nodes: {
                dataSource: new DevExpress.data.ArrayStore({
                    key: "this",
                    data: employees
                }),
                keyExpr: "ID",
                textExpr: "Title",
                itemsExpr: "Items",
            },
        });
    });
    var employees = [{
        "ID": 3,
        "Full_Name": "Arthur Miller",
        "Title": "CTO",
        "Items": [{
            "ID": 6,
            "Full_Name": "Brett Wade",
            "Title": "IT Manager",
            "Items": [{
                "ID": 21,
                "Full_Name": "Taylor Riley",
                "Title": "Network Admin",
            }, {
                "ID": 23,
                "Full_Name": "Wally Hobbs",
                "Title": "Programmer",
            }, {
                "ID": 24,
                "Full_Name": "Brad Jameson",
                "Title": "Programmer",
            }]
        }, {
            "ID": 9,
            "Full_Name": "Barb Banks",
            "Title": "Support Manager",
            "Items": [{
                "ID": 18,
                "Full_Name": "James Anderson",
                "Title": "Support Assistant",
            }]
        }]
    }];

Diagram - Node and Edge Arrays

Diagram Layout

The UI component creates a diagram layout based on the algorithm specified by the autoLayout.orientation and autoLayout.type properties.

index.js
    $(function() {
        $("#diagram").dxDiagram({
            nodes: {
                autoLayout: {
                    orientation: "horizontal"
                    type: "tree",
                },
                ...
            },
        });
    });

You can create a diagram layout based on shape coordinates maintained in a data source. Set the leftExpr and topExpr properties to names of data source fields that provide shape coordinates.

If you bind a Diagram to an array of edges, you can specify a shape's connection point where an edge begins (fromPointIndexExpr) and ends (toPointIndexExpr) and provide additional points for connectors with the pointsExpr property.

Shape and edge point coordinates are specified in units.

NOTE

If the autoLayout.type property is set to auto (default value), and both the leftExpr and topExpr properties are specified, the autolayout feature is disabled. The UI component creates a diagram layout based on the provided coordinates. If the position properties are not specified, the auto type denotes the layered layout.

If the autoLayout.type property is set to layered or tree, predefined shape coordinates (leftExpr and topExpr) and edge points (pointsExpr) are ignored.

index.js
data.js
$(function() {
    $("#diagram").dxDiagram({
        nodes: {
            dataSource: new DevExpress.data.ArrayStore({
                key: "this",
                data: orgItems
            }),
            autoLayout: {
                type: "off"
            },
            keyExpr: "key",
            leftExpr: "left",
            textExpr: "text",
            topExpr: "top",
        },
        edges: {
            dataSource: new DevExpress.data.ArrayStore({
                key: "this",
                data: orgLinks
            }),
            keyExpr: "key",
            fromExpr: "from",
            toExpr: "to",
            fromPointIndexExpr: "fromPoint",
            toPointIndexExpr: "toPoint",
            pointsExpr: "points",
        },
        units: "in",
    });
});
var orgItems = [
  {  
        key: "101",
        left: 0.5,
        text: "Product Manager",
        top: 0.875,
  },
  {  
        key: "102",
        left: 2.5,
        text: "Team",
        top: 0.5,
    },
];
var orgLinks = [  
  {  
        key: "1",
        from: "101",
        to: "102",
        fromPoint: 1,
        toPoint: 3,
        points: [{x:1.5,y:1.125},{x:1.75,y:0.875},{x:2.5,y:0.875}],
  },
];

The Diagram UI component reloads the diagram every time the data source changes. The onRequestLayoutUpdate function is executed after diagram data is reloaded and allows you to specify whether the UI component should update the diagram layout.

Optional Binding Expressions

The Diagram allows you to bind a number of shape and connector visual properties, like type, size, and style.

NOTE
If a binding property is undefined, the corresponding shape or connector property value is maintained inside the loaded Diagram UI component and is lost after a page is reloaded.

Diagram - Data Binding Options

Node property Value the property should return Sample return value
containerChildrenExpr A container's nested items. This property is in effect for verticalContainer or horizontalContainer nodes. Excludes containerKeyExpr. [{"id":"112","text":"Ana\nTrujillo"}, {"id":"113","text":"Antonio\nMoreno"}]
containerKeyExpr A parent container node key. The parent container node must be of the verticalContainer or horizontalContainer type. Excludes containerChildrenExpr. "102"
customDataExpr A node's custom data. -
heightExpr A node's height, in units. 0.625
imageUrlExpr A node's image URL or Base64 encoded image. This property is in effect for nodes of the cardWithImageOnLeft, cardWithImageOnTop, or cardWithImageOnRight type. "images/employees/30.png"
leftExpr The x-coordinate of a node's left border, in units. 0.5
lockedExpr A value that indicates whether a node is locked.
Should return true or false.
true
styleExpr A node's style. { "stroke": "red" }
textExpr A node's text. "ASP.NET"
textStyleExpr A node's text style. { "font-weight": "bold", "text-decoration": "underline" }
topExpr The y-coordinate of a node's top border, in units. 0.875
typeExpr A node's shape type. Built-in shape types are shown in the Shape Types section. "horizontalContainer"
widthExpr A node's width, in units. 2
zIndexExpr A node's z-index. 1
NOTE
If you bind a Diagram to a linear or hierarchical array, edge binding properties are not in effect, because connectors are not bound to specific edges. This is why the storage of connector styles in a data source is not supported.
Edge property Value the property should return Sample return value
customDataExpr An edge's custom data. -
fromExpr An edge's start node key. "101",
fromLineEndExpr An edge's line start tip.
Should return "arrow", "filledTriangle", "outlinedTriangle", or "none".
"none"
fromPointIndexExpr A shape's connection point index where an edge begins. 1
lineTypeExpr An edge's line type.
Should return "orthogonal" or "straight".
"straight"
lockedExpr A value that indicates whether a node is locked.
Should return true or false.
false
pointsExpr An edge's key points. [{x:1.5,y:1.125},{x:1.75,y:0.875},{x:2.5,y:0.875}]
styleExpr An edge's style. {"stroke-dasharray":"4"}
textExpr An edge's text. "text" or { 0.3: "text1", 0.8: "text2" }
textStyleExpr An edge's text style. { "font-weight": "bold"}
toExpr An edge's end node key. "102",
toLineEndExpr An edge's line end tip.
Should return "arrow", "filledTriangle", "outlinedTriangle", or "none".
"filledTriangle"
toPointIndexExpr A shape's connection point index where an edge ends. 11
zIndexExpr An edge's z-index. 0

You can set a binding property to the name of a data source field that supplies item values, or to an expression that returns a constant value or calculates a value in runtime based on conditions.

If your diagram includes container shapes, define the containerKeyExpr property to store information about a parent container in the data source. Otherwise, this information will be lost.

Diagram - Data Bound Diagram

index.js
data.js
$(function() {
    $("#diagram").dxDiagram({
        nodes: {
            dataSource: new DevExpress.data.ArrayStore({
                key: "this",
                data: orgItems
            }),
            autoLayout: {
                type: "off"
            },
            containerKeyExpr: "containerKey",
            heightExpr: "height",
            imageUrlExpr: "imageUrl",
            keyExpr: "key",
            leftExpr: "left",
            lockedExpr: "locked",
            styleExpr: function(obj) {if (obj.type.includes("Container")) return {"stroke": "red"}},
            textExpr: "text",
            textStyleExpr: "textStyle",
            topExpr: "top",
            typeExpr: "type",
            widthExpr: "width",
            zIndexExpr: "zIndex",
        },
        edges: {
            dataSource: new DevExpress.data.ArrayStore({
                key: "this",
                data: orgLinks
            }),
            fromExpr: "from",
            fromLineEndExpr: function() {return "none"},
            fromPointIndexExpr: "fromPointIndex",
            keyExpr: "key",
            lineTypeExpr: function() {return "straight"},
            lockedExpr: "locked",
            pointsExpr: "points",
            styleExpr: function() {return ({"stroke-dasharray":"4"})},
            textExpr: "text",
            textStyleExpr: "textStyle",
            toExpr: "to",
            toLineEndExpr: function() {return "arrow"},
            toPointIndexExpr: "toPointIndex",
        },
    });
});
var orgItems = [
    {  
        height: 0.625,
        key: "101",
        left: 0.5,
        locked: true,
        text: "Product Manager",
        textStyle: { "font-weight": "bold", "text-decoration": "underline" },
        top: 0.875,
        type: "rectangle",
        width: 1,
        zIndex: 2,
    },
    {  
        height: 1.375,
        key: "102",
        left: 2.5,
        locked: false,
        text: "Team",
        textStyle: { "font-weight": "bold", "text-decoration": "underline" },
        top: 0.5,
        type: "horizontalContainer",
        width: 2,
        zIndex: 1,
    },{
        height: 0.5,
        imageUrl: "images/employees/30.png",
        key: "103",
        left: 2.875,
        text: "Team Leader",
        top: 0.625,
        type: "cardWithImageOnLeft",
        width: 1.5,
        containerKey: "102",
    },{
        height: 0.5,
        key: "104",
        left: 2.875,
        text: "Developers",
        top: 1.25,
        type: "rectangle",
        width: 1.5,
        containerKey: "102",
    }
];
var orgLinks = [  
    {  
        from: "101",
        fromPointIndex: 1,
        key: "1",
        locked: false,
        points: [{x:1.5,y:1.125},{x:1.75,y:0.875},{x:2.5,y:0.875}],
        text: "Task",
        textStyle: { "font-weight": "bold"},
        to: "102",
        toPointIndex: 11,
    },
];