documentationfor yFiles for HTML 2.6

Setting Defaults for new Items

IGraph’s creation methods for elements allow creation of elements without explicitly specifying initial properties like a style or an initial geometry. If an initial value is not explicitly specified, a default value which is defined on IGraph’s nodeDefaults or edgeDefaults properties is used.

Defaults for graph elements
Graph Item Property Type
nodes (not group nodes)nodeDefaultsINodeDefaults
edgesedgeDefaultsIEdgeDefaults
node labels (not at groups)nodeDefaults.labelsILabelDefaults
edge labelsedgeDefaults.labelsILabelDefaults
ports at nodes (not at groups)nodeDefaults.portsIPortDefaults
labels of ports at nodes (not at groups)nodeDefaults.ports.labelsILabelDefaults
ports at edgesedgeDefaults.portsIPortDefaults
labels of ports at edgesedgeDefaults.ports.labelsILabelDefaults
group nodesgroupNodeDefaultsINodeDefaults
labels at group nodesgroupNodeDefaults.labelsILabelDefaults
ports at group nodesgroupNodeDefaults.portsIPortDefaults
labels of ports at group nodesgroupNodeDefaults.ports.labelsILabelDefaults

Note that the defaults for labels and ports are not defined in a property of IGraph but in properties of the INodeDefaults and IEdgeDefaults, respectively. This allows different default configurations for node and edge labels and ports. Similarly, the defaults for port labels are defined in the IPortDefaults which themselves are defined in the defaults of the port’s owner.

Set the default values for newly created nodes and their labels
// Get the node defaults
const nodeDefaults = graph.nodeDefaults
// define a new default style
const style = new ShapeNodeStyle({
  fill: Fill.ORANGE,
  shape: ShapeNodeShape.ELLIPSE
})

// set a new default style
nodeDefaults.style = style
// set a new default size
nodeDefaults.size = new Size(40, 40)
// set a new default label model parameter
nodeDefaults.labels.layoutParameter = ExteriorLabelModel.SOUTH

If no style is provided upon creation the IGraph implementations delegate to the getStyleInstance method to get the style instance to use for the newly created item. Depending on the value of shareStyleInstance this method either returns the style instance provided by style or a clone thereof.

shareStyleInstance
If set to true the same style instance is used as style for each newly created element. Otherwise, a clone of the default style is used. Default is true.
getStyleInstance(): INodeStyle
Queried to return a default style instance for a newly created graph item. Depending on the value of shareStyleInstance this is either the instance provided by style or a clone of it.

Shared vs. cloned styles
const defaultStyle = new ShapeNodeStyle()
graph.nodeDefaults.style = defaultStyle

// Share style instances
graph.nodeDefaults.shareStyleInstance = true
const n1 = graph.createNodeAt(new Point(0, 0))
const n2 = graph.createNodeAt(new Point(0, 50))
// At this point, n1.Style and n2.Style are the exact same instance as defaultStyle
defaultStyle.fill = Fill.RED
graph.invalidateDisplays() // n1 and n2 both turn red, too

// Clone style instances
graph.nodeDefaults.shareStyleInstance = false
const n3 = graph.createNodeAt(new Point(0, 100))
const n4 = graph.createNodeAt(new Point(0, 150))
// At this point, n3.Style, n4.Style, and defaultStyle are all different instances
defaultStyle.fill = Fill.YELLOW // n3 and n4 don't change their color

Note that although shown for INodeDefaults the above methods are defined on IEdgeDefaults, ILabelDefaults, and IPortDefaults, too.

It is possible to set a new INodeDefaults instance here, as well. That way, it is possible to share the same defaults for group nodes and normal nodes:

// Use the same defaults for nodes and group nodes
graph.groupNodeDefaults = graph.nodeDefaults
graph.nodeDefaults.style = new ShapeNodeStyle({
  shape: 'ellipse',
  fill: 'yellow'
})
// Use the same defaults for nodes and group nodes
graph.groupNodeDefaults = graph.nodeDefaults
graph.nodeDefaults.style = new ShapeNodeStyle({ shape: 'ellipse', fill: 'yellow' })

or to share only the label defaults:

// Use different defaults for nodes and group nodes ...
graph.nodeDefaults.style = new ShapeNodeStyle({
  shape: 'ellipse',
  fill: 'yellow'
})
graph.groupNodeDefaults.style = new GroupNodeStyle({
  tabFill: 'light-blue'
})
// ... but use the same label defaults
graph.groupNodeDefaults.labels = graph.nodeDefaults.labels
graph.nodeDefaults.labels.style = new DefaultLabelStyle({
  backgroundFill: 'dark-gray'
})
graph.nodeDefaults.labels.layoutParameter = ExteriorLabelModel.SOUTH
// Use different defaults for nodes and group nodes ...
graph.nodeDefaults.style = new ShapeNodeStyle({ shape: 'ellipse', fill: 'yellow' })
graph.groupNodeDefaults.style = new GroupNodeStyle({ tabFill: 'light-blue' })
// ... but use the same label defaults
graph.groupNodeDefaults.labels = graph.nodeDefaults.labels
graph.nodeDefaults.labels.style = new DefaultLabelStyle({ backgroundFill: 'dark-gray' })
graph.nodeDefaults.labels.layoutParameter = ExteriorLabelModel.SOUTH

or to keep pre-configured defaults:

const darkTheme = new NodeDefaults({
  labels: new LabelDefaults({
    style: new DefaultLabelStyle({
      backgroundFill: 'black',
      backgroundStroke: 'white',
      textFill: 'light-gray'
    })
  }),
  style: new ShapeNodeStyle({ fill: 'black', stroke: 'white' })
})
const classicTheme = new NodeDefaults({
  labels: new LabelDefaults({
    style: new DefaultLabelStyle({
      backgroundFill: 'white',
      backgroundStroke: 'black',
      textFill: 'black'
    })
  }),
  style: new ShapeNodeStyle({ fill: 'orange' })
})
graph.nodeDefaults = useDarkTheme ? darkTheme : classicTheme

The IPortDefaults.autoCleanUp property plays a special role in that it controls a behavior, rather than providing a default value:

autoCleanUp
If set to true a port is automatically removed when the last edge connected to it is removed. That means that ports can implicitly get removed. Default is true.

Removing ports when an edge is removed
const node1 = graph.createNode()
const node2 = graph.createNode()
const port11 = graph.addPort(node1)
const port12 = graph.addPort(node1)
const port2 = graph.addPort(node2)
const edge1 = graph.createEdge(port11, port2)
const edge2 = graph.createEdge(port12, port2)

// enable auto cleanup
graph.nodeDefaults.ports.autoCleanUp = true
graph.remove(edge1)
// port11 is removed with the edge
console.log(graph.contains(port11)) // false
// port2 is not removed since edge2 still is linked to it
console.log(graph.contains(port2)) // true

// disable auto cleanup
graph.nodeDefaults.ports.autoCleanUp = false
graph.remove(edge2)
// no port is removed with the edge now
console.log(graph.contains(port12)) // true
console.log(graph.contains(port2)) // true