documentationfor yFiles for HTML 2.6

Automatic Type Conversion

With automatic type conversion, the yFiles Class Framework offers a convenient way to specify complex yFiles types with a short-hand syntax. In parameter lists, parameter objects, or property setters, these convertible types can be assigned from a substitute type, e.g. a simple string. The substitute type is then converted into the actual type at runtime.

That way, it is often possible to write more compact code especially for object initialization. The code also becomes more readable because a lot of the replacement strings are similar to well-known CSS declarations. The disadvantage is that code completion cannot strictly check all the valid substitute types.

If a property or method takes a convertible type, it is marked with CONVERSION in the API documentation, e.g., fill. A paragraph in the class description of each convertible type describes the available conversions for this type.

In the TypeScript type definition file, public properties don’t support automatic type conversion, and the IDE will display warnings when assigning type-convertible values to public properties. This is due to restrictions in the TypeScript language that require the types of property getters and setters to be the same.

Since the transpiled JavaScript code will work nevertheless, these warnings can be safely ignored if the property is marked with CONVERSION in the API documentation. Alternatively, use the static from methods of convertible types, e.g., from. These methods convert convertible values into an instance of the actual type.

Most types that support automatic type conversion will work for all public properties, and parameters of constructors and factory methods. For performance reasons, some protected methods and less-frequently called but performance critical methods don’t allow automatic type conversion. If in doubt, consult the documentation and look for the CONVERSION tag. Be aware that you cannot put short-hand variants of convertible types into collections. They will only be converted automatically if passed directly as arguments to the yFiles API. The runtime type checks should detect most invalid usages, but without debugging checks, runtime behavior can be undefined.

Enums

Enum types in general are convertible. Almost everywhere where enums values are expected, they can be substituted with a simple string consisting of the enum value’s name. The name is accepted in uppercase and lowercase letters. In case a name consists of several words, they can be separated with the - or _ character.

When enum values can be combined bit-wise, you can either use the |, +, and , characters to combine the string representations of several enum values in a single string or specify them in an array of strings, like in the following example:

const labelStyle = new DefaultLabelStyle({
  horizontalTextAlignment: 'center',
  verticalTextAlignment: 'CENTER'
})

graphComponent.inputMode.selectableItems = 'node,edge'
graphComponent.inputMode.selectableItems = 'NODE|EDGE'
graphComponent.inputMode.selectableItems = ['NODE', 'EDGE']

Colors, Fills, and Strokes

Colors and Fills can be defined as CSS color strings. Strokes are converted from strings adhering to the CSS shorthand properties for border definition. Number values are also supported to conveniently use hexadecimal notations and numeric calculations.

const nodeStyle = new ShapeNodeStyle({
  fill: 'blue',
  stroke: "3px dashed red"
})
nodeStyle.fill = 'hsl(225, 98%, 60%)'
nodeStyle.fill = 'rgba(255, 255, 0, 0.5)'
nodeStyle.fill = new SolidColorFill('rgb(255, 255, 0)')
nodeStyle.stroke = '#336699'
nodeStyle.stroke = 0xff00ff

Fonts

Fonts can be converted from strings that adhere to the CSS shorthand property for fonts.

const labelStyle = new DefaultLabelStyle({
  font: 'bold 16px sans-serif'
})
labelStyle.font = 'italic Tahoma'
labelStyle.font = 'normal xx-large Arial'

Rectangles, Points, Sizes, and Insets

Geometric classes like IRectangle, IPoint, and ISize are defined using numbers for x, y, width and height. Instead of using the constructor, they can be converted from Arrays or plain objects.

graph.createNode([10, 10, 50, 20])
graph.createNode({ layout: { x: 10, y: 10, width: 50, height: 20 }})

graph.createNodeAt([10, 10])
graph.createNodeAt({ location: { x: 10, y: 10 }})

graphComponent.doubleClickSize = [20, 20]
graphComponent.doubleClickSize = { width: 20, height: 30 }

Insets can either be substituted with a single number that describes the insets for all sides, an array, or a plain object. They work similar to the short-hand for CSS margins.

const rectangle = new Rect(0, 0, 10, 10)
rectangle.getEnlarged(10)               // horizontal and vertical
rectangle.getEnlarged([5, 10])          // vertical, horizontal
rectangle.getEnlarged([15, 10, 5])      // top, horizontal, bottom
rectangle.getEnlarged([5, 10, 15, 20])  // top, right, bottom, left

rectangle.getEnlarged({ left: 5, top: 10, bottom: 5, right: 10 })

When using plain objects to describe a convertible type, they may not work together with overloads. That is because if the substitute object is the only parameter, it creates an ambiguous overload with the parameter object notation. Also, it may not be possible to determine the right overload at runtime if there are multiple real overloads. However, using a substitute object in a parameter list or as a named option argument in a parameter object is valid unless the resulting type is ambiguous.

Arrows

Most Arrows are described by a shape, a scale, and a color. A string which provides some or all of these values can be used to define an Arrow.

const edgeStyle = new PolylineEdgeStyle({
  sourceArrow: 'circle',
  targetArrow: 'green xx-large diamond',
})
edgeStyle.sourceArrow = 'blue simple'
edgeStyle.targetArrow = 'rgb(200, 200, 0) simple'

Cursors

To set one of the default Cursors, it is possible to use the name of the constant as a string. Similar to enum values, the name is accepted in uppercase and lowercase letters, and in case a name consists of several words, they can be separated with the - or _ character.

const itemHoverInputMode = graphComponent.inputMode.itemHoverInputMode
itemHoverInputMode.hoverCursor = 'grab'
itemHoverInputMode.hoverCursor = 'MOVE'

TimeSpan

TimeSpan is defined using a simple number representing the duration in milliseconds, or through one of the static factory methods. A more convenient and readable way is to use strings that are converted into TimeSpan objects.

graphComponent.doubleClickTime = 300  //milliseconds
graphComponent.doubleClickTime = '4s'
graphComponent.doubleClickTime = '250ms'
graphComponent.doubleClickTime = '0:23:10'
graphComponent.doubleClickTime = '1m 0.5s'

Enumerables, Collections, and Lists

Arrays, as well as JavaScript Sets can be converted to IEnumerable<T>, ICollection<T>, and IList<T>.

graph.groupNodes([child1, child2, child3])
graph.groupNodes(new Set([child1, child2]))

In fact any, value that implements the 'iterable' protocol will also be converted automatically. For example the return value of a Generator function:

let node = graph.createNode()

function* createNodeGenerator(){
  yield node
  let i = 0
  for (let n of graph.nodes) {
    if (i++ %2 === 1) yield n
  }
}

// obtain an iterator from the generator
const generator = createNodeGenerator()
graph.groupNodes(generator)

Be careful with iterators when converting them to IEnumerable, though: Iterator instances can only be iterated, once. So if the iterator is passed to an API that expects an IEnumerable<T>, it will be converted to a live enumerable that will enumerate all the values in the iterable on request. Once the iterable has completed, the enumerator will complete, too. But unlike most IEnumerable implementations it will be unable to enumerate the values, again, because the iterable is complete and cannot be reset. If the API expects a List, however, the iterable will be iterated immediately, once, and the values will be cached in the list that is passed on to the API.

If you want to let the receiver of the value be able to enumerate the values of an iterator more than once, either cache the values in an iterable, first, or use a generator function, that can be called, again. If you don’t want it to be dynamic, or generation is computationally expensive, consider caching it:

let node = graph.createNode()

function* createNodeGenerator(){
  yield node
  let i = 0
  for (let n of graph.nodes) {
    if (i++ %2 === 1) yield n
  }
}

// pass the generator function without calling it,
// yFiles will create an IEnumerable that can be re-enumerated, dynamically,
// any number of times.
graph.groupNodes(createNodeGenerator)

// cache the generated values in an iterable that can be iterated more than once
graph.groupNodes(Array.from(createNodeGenerator()))
// or
graph.groupNodes([...createNodeGenerator()])
// or
graph.groupNodes(new Set(createNodeGenerator()))

ItemMapping, ItemCollection, SingleItem

These types are used in LayoutData and graph algorithm wrappers to provide several properties to specify additional data for the graph in different ways. Type conversion allows you to omit these properties and directly assign the property of the actual LayoutData or graph algorithm wrapper.

// ItemMapping
const hierarchicLayoutData = new HierarchicLayoutData()
// omitting 'constant'
hierarchicLayoutData.sourcePortCandidates = new List([
  PortCandidate.createCandidate('EAST', 0),
  PortCandidate.createCandidate('WEST', 0)
])
// omitting 'delegate'
hierarchicLayoutData.sourcePortCandidates = () =>
  east ? PortCandidate.createCandidate('EAST', 0) : PortCandidate.createCandidate('WEST', 0)
// omitting 'mapper'
hierarchicLayoutData.sourcePortCandidates = new Mapper()

// ItemCollection
const treeLayoutData = new TreeLayoutData()
// omitting 'delegate'
treeLayoutData.assistantNodes = node => isAssistant(node)
// omitting 'constant'
treeLayoutData.assistantNodes = node1
// omitting 'items'
treeLayoutData.assistantNodes = [node1, node2]
// omitting 'mapper'
treeLayoutData.assistantNodes = new Mapper()
// omitting 'source'
treeLayoutData.assistantNodes = graphComponent.selection.selectedNodes

// SingleItem
const shortestPath = new ShortestPath()
// omitting 'constant'
shortestPath.source = node1
// omitting 'delegate'
shortestPath.source = node => isSource(node)
// omitting 'source'
shortestPath.source = graphComponent.selection.selectedNodes

All these types provide option overloads with their constructors, too, therefore instantiations can be simplified further, for example:

const shortestPath = new ShortestPath({
  source: graphComponent.selection.selectedNodes,
  costs: 20,
  sink: node => isSink(node)
})

IMapper

The IMapper<K,V> type is used to associate additional information about graph items in layout algorithms. IMapper<K,V>s can be converted from native JavaScript Map instances.

const layerIndexMap = new Map()
// use a JavaScript Map as IMapper
const hierarchicLayoutData = new HierarchicLayoutData({
  layerIndices: layerIndexMap
})