documentationfor yFiles for HTML 2.6

Using SVG Templates in Styles

If you want to use native SVG templates as part of your visualization, yFiles for HTML ships with predefined style implementations for nodes, labels, ports, and stripes that support this:

Each of these styles has an property to provide the id of the render template element that should be used for visualization, for example styleResourceKey. Note that the id key can also be passed as constructor parameter.

Render templates are pre-defined SVG snippets that are defined in one or more script elements that act as a container to provide the snippets. A <script> element containing templates needs to be included in an application’s main HTML file and is identified by the value "text/yfiles-template" in its type attribute. During runtime, the child elements of the template scripts are parsed and made available for the template styles. All top-level child elements with an 'id' attribute can be referenced by their id. The contents of top-level <defs> elements in the template script can be referenced by all templates that are defined within the same script. This way, resources can be shared among multiple templates.

The following example shows a template SVG with a simple render template for nodes:

<script type="text/yfiles-template">
<g id="myNodeStyleTemplate">
  <rect fill="blue" stroke="black" stroke-width="3"
        rx="8" ry="8" width="250" height="100"/>
  <rect fill="red" stroke="black" stroke-width="3"
        rx="4" ry="4" width="150" height="50"
        transform="translate(50 25)"/>
</g>
</script>

With this template script included in an application’s main HTML file, the unique ID of the enclosing <g> element can be used as the key when creating a new TemplateNodeStyle instance:

graph.nodeDefaults.style = new TemplateNodeStyle('myNodeStyleTemplate')

Using Strings as Templates

Besides the template styles introduced above, yFiles for HTML ships with style implementations which support SVG snippets provided as strings:

The string has to be set to the svgContent property or passed to the constructor.

const svgTemplate =
  "<rect fill='#A6CBF0' stroke='#2C4E86' stroke-width='2' " +
  "width='120' height='80'>" +
  '</rect>' +
  "<text transform='translate(10 20)' data-content='Data Content' " +
  "style='font-size:18px;'></text>"

const style = new StringTemplateNodeStyle(svgTemplate)

Note that the SVG snippet does not declare the SVG namespace itself. After parsing the resulting SVG elements are automatically created in the SVG namespace before they are added to the DOM.

Using Data Binding

Template styles also provide a mechanism for data binding. SVG attribute values can be bound to any property available in the graph element’s tag property as well as certain standard template properties such as itemSelected and itemFocused available in the template context.

If the bound object provides the method addPropertyChangedListener(listener: function), or implements the IPropertyObservable interface, and calls the registered listeners, changes to the bound property are immediately reflected in the visualization.

Binding also provides support for converters and converter parameters as well as binding property paths.

Bindings are dynamically replaced with the bound values by the binding engine at runtime. "Normal" bindings are resolved on the graph element’s tag property. For example, if there is an object stored in the element’s tag that has the property width, you can bind to the value of this property with the string "{Binding width}":

<rect fill="blue" width="{Binding width}" height="100"/>

Bindings work on all standard SVG attributes.

<use xlink:href="{Binding uri}"/>

Adding a binding using the custom attribute data-content sets the content of the element to the bound value. The following example sets the content of the <text> element to the value of the property name (of an object stored in the element’s tag).

<text data-content="{Binding name}"></text>

The tag object itself can be bound by omitting to specify the binding property. Please note though that assigning a different object to the graph item’s tag will not automatically update the bindings.

The following example will result in <text>Lorem ipsum</text>

<!-- node.tag = 'Lorem ipsum' -->
<text data-content="{Binding}"></text>

Template Binding

Template bindings are resolved on a graph element’s template context. This can be used to modify the element based on its selection state, for example. Also, custom data can be stored in the template style’s styleTag property, which you can also bind to using a template binding.

Supported TemplateBinding properties for all graph items
Property Purpose
widthThe width of the graph element
heightThe height of the graph element
boundsThe bounding rectangle of the graph element
canvasComponentThe GraphComponent the element is rendered in
zoomThe current zoom level of the GraphComponent
styleTagThe styleTag property of the element’s style instance
itemSelectedWhether the element is selected
itemFocusedWhether the element has the focus
itemHighlightedWhether the element is highlighted

In a label template, template bindings are resolved on an extended label template context that provides the following additional properties:

Additional TemplateBinding properties for labels
Property Purpose
labelTextThe label’s text
isFlippedWhether the label is flipped
isUpsideDownWhether the label is currently rendered upside down

The following template binding sets the fill to the value stored in the style’s styleTag property:

<rect fill="{TemplateBinding styleTag}"/>

The template binding in the data-content attribute sets the content of the SVG group to the value stored in the template style’s styleTag property (this can be an SVG element!):

<g data-content="{TemplateBinding styleTag}"/>

Bindings in String Template Styles

In string template styles, bindings work just the same as described above. The string template example mentioned in Using Strings as Templates is easily adapted to using bindings:

const svgTemplate =
  "<rect fill='#A6CBF0' stroke='#2C4E86' stroke-width='2' " +
  "width='{TemplateBinding width}' height='{TemplateBinding height}'>" +
  '</rect>' +
  "<text transform='translate(10 20)' data-content='{Binding name}' " +
  "style='font-size:18px;'></text>"

const style = new StringTemplateNodeStyle(svgTemplate)

Property Paths

The binding engine supports property paths. This means, bindings can not only be resolved directly on the properties of the bound objects, but on properties of objects stored in properties of the bound objects, etc., also.

The following example binds the property color of the object that is stored in the styleTag property.

<rect fill="{TemplateBinding styleTag.color}"/>

Converters

Bindings can specify converters and converter parameters. Converters are simple functions with the signature function(value:Object, parameter:Object):Object.

A converter has to be registered under its name either in the converter store or with the window object before it can be used. The converter store is shared among all TemplateStyles. It can be accessed by the static property CONVERTERS on the respective TemplateStyle class. At runtime, the converter method is located by name in the converter store - if it is not found there the function is located on the window object. The converter is called with the resolved binding value an optionally the converter parameter. The converter is in charge of returning an object that is used as the value of the attribute containing the binding.

Note that, if the binding was specified in a data-content attribute, the converter may also return an SVG element that is set as a child node to the element in the DOM containing the data binding.

Using a simple conversion function and registering it with the converter store:

TemplateNodeStyle.CONVERTERS.colorConverter = (value, parameter) => {
  // converts a bool into a color
  if (typeof value === 'boolean') {
    return value ? '#00FF00' : '#FF0000'
  }
  return '#000000'
}TemplateNodeStyle.CONVERTERS.colorConverter = (value: any, parameter: any): '#00FF00' | '#FF0000' | '#000000' => {
  // converts a bool into a color
  if (typeof value === 'boolean') {
    return value ? '#00FF00' : '#FF0000'
  }
  return '#000000'
}

Using the converter in a binding within a render template:

<rect fill="{Binding isPresent, Converter=colorConverter}"/>

Using a converter with a converter parameter to prefix the bound value with the string "http://":

<text data-content="{Binding url, Converter=prefixConverter, Parameter=http://}"/>

The definition of the converter shows how the converter parameter is used in the convert method:

TemplateNodeStyle.CONVERTERS.prefixConverter = (value, parameter) => {
  if (typeof value === 'string' && typeof parameter === 'string') {
    return parameter + value
  }
  return value
}TemplateNodeStyle.CONVERTERS.prefixConverter = (value: any, parameter: any): any => {
  if (typeof value === 'string' && typeof parameter === 'string') {
    return parameter + value
  }
  return value
}

Notifying of Property Changes

If the bound object provides the method addPropertyChangedListener(listener: function), or implements the IPropertyObservable interface, it should call the registered listeners when a property value has changed. The binding mechanism registers a listener and updates the template instance if the name given in the listener argument matches the property’s name.

To allow the binding mechanism to properly clean up unused bindings, the bound object should also provide the method removePropertyChangedListener(listener: function) which should remove the given listener.

An arbitrary object can also be made observable for the binding engine by using one of the static makeObservable convenience methods of the template style implementations. In this case, the update has to be triggered by calling the function firePropertyChanged(propertyName) on the bound object when the value of a bound property has changed.

// create a data object to put in the node tag
// the node template binds to color, e.g. <rect fill="{Binding color}">
const data = {
  color: 'red'
}
// makes the data object observable and adds the function 'firePropertyChanged' on data
TemplateNodeStyle.makeObservable(data)
// change color and notify the binding engine of the change
// to update the visual template automatically
data.color = 'green'
data.firePropertyChanged('color')// create a data object to put in the node tag
// the node template binds to color, e.g. <rect fill="{Binding color}">
const data = {
  color: 'red'
}
// makes the data object observable and adds the function 'firePropertyChanged' on data
TemplateNodeStyle.makeObservable(data)
// change color and notify the binding engine of the change
// to update the visual template automatically
data.color = 'green'
;(data as any).firePropertyChanged('color')

State Dependent CSS classes

Depending on the state of the item, the following CSS classes are added to the root element of the template:

  • yfiles-selected
  • yfiles-focused
  • yfiles-highlighted

Text Wrapping in a Template Style

TextWrapConverter is a built-in converter function which emits wrapped text as svg elements. It can be used to display wrapped text in a template style.

To use the TextWrapConverter the template style must include a <g> element that binds a property containing the text to be wrapped to data-content. As Converter function TextWrapConverter must be specified. The converter’s parameters are passed using a shorthand notation for width, height, font, trimming and color.

The shorthand syntax must satisfy the following expression:

width height [;font[;trimming[;color]?]?]?

where:
"width" is an integer
"height" is an integer
"font" is a css-like font shorthand
"trimming" is "none"|"word"|"character"|"character-ellipsis"|"word-ellipsis"
"color" is a css color shorthand

A full template might look like this:

<g id="NodeTemplate">
  <rect stroke="none" fill="lightblue" rx="4" ry="4" width="{TemplateBinding width}" height="{TemplateBinding height}"></rect>
  <g data-content="{Binding text, Converter=TextWrapConverter, Parameter=100 50; 20px sans-serif; character-ellipsis; red}"></g>
</g>

Tutorial Demo Code

The Organization Chart demo shows how to use a TemplateNodeStyle for a complex node visualization. It also demonstrates the aspects of data binding and converters.