documentationfor yFiles for HTML 2.6

Separating Style and Renderer

NodeStyleBase<TVisual> hides the implementation of multiple interfaces in favor of convenience for the application developer. The only method that you really need to implement is createVisual, which makes it a convenient starting point when writing your own styles.

In yFiles for HTML’s rendering engine, the instances that actually produce the visual representations of an item are of type IVisualCreator. In the graph element visualization process, those IVisualCreator instances are returned for a certain object by style renderers. The style interfaces themselves are only responsible to hold a suitable renderer instance. For example, INodeStyle has a renderer property that returns an object of type INodeStyleRenderer. There is a corresponding renderer interface for each style interface in yFiles for HTML (INodeStyleRenderer for INodeStyle, ILabelStyleRenderer for ILabelStyle and so on).

To acquire the visual representation of an element, the framework queries the style for its renderer, and calls the appropriate methods on the IVisualCreator that is returned by the renderer.

Relationship between styles, renderers, and IVisualCreators at the example of node styles
custom styles separating style classes style renderer visual creator relation

The abstract style classes hide this separation for convenience and simplicity. However, separating the style and its renderer actually has advantages in certain use-cases.

On an interface level, the styles have only one method that is supposed to provide the style renderer (e.g. INodeStyle.renderer ). Aside from that, the style itself is meant to hold the state that is needed for rendering. Clients should be able to control properties of the rendering on the style, for example, the used colors or stroke.

Renderers, however, are meant to contain the logic that converts the state held by the style to a visualization on the canvas. The yFiles for HTML rendering engine also uses this renderer to handle application logic that depends on aspects of the visualization (such as hit testing, or visibility checks). Because of this, the renderer interfaces themselves are broader than necessary for just rendering items. Aside from the IVisualCreator, the renderer classes are responsible for providing IHitTestable, IMarqueeTestable, ILassoTestable, IVisibilityTestable, and IBoundsProvider implementations. Additionally, the renderer of INodeStyles and IEdgeStyles provides implementations of the IShapeGeometry and the IPathGeometry interface, respectively. All these interfaces are discussed in the section Refining a Style’s Behavior.

When separating style and renderer classes, a flyweight pattern can be implemented where renderers can be shared amongst styles. Two styles of the same type can also be created with different renderers to interpret their properties differently or an existing style and renderer pair can be customized. This is shown in the section Customizing Predefined Styles.

Visuals can and should share information amongst each other where applicable. This can be done by storing the relevant information on the renderer instance the Visuals were created from.

Sharing data between Visuals speeds up the creation and updating process of new Visuals since resources can be allocated efficiently. This improves memory usage of your application.