yfiles-nodestyle-basic
Creates basic custom node styles by extending NodeStyleBase and implementing createVisual/updateVisual methods. Handles SVG rendering, visual caching, and performance optimization. Use when creating c
SKILL.mdskills/yfiles-nodestyle-basic/SKILL.md
GitHubBasic Custom Node Styles
Create custom node visualizations by extending NodeStyleBase and implementing SVG rendering with typed visual caching.
Before Creating
Always query the yFiles MCP for current API:
yfiles:yfiles_get_symbol_details(name="NodeStyleBase")
yfiles:yfiles_get_symbol_details(name="TaggedSvgVisual")
yfiles:yfiles_list_members(name="NodeStyleBase")
yfiles:yfiles_search_documentation(query="custom node style")
Quick Start (Minimal)
The simplest possible style — no caching, no updateVisual. Suitable for prototyping but not recommended for larger graphs.
import { NodeStyleBase, SvgVisual, type IRenderContext, type INode } from '@yfiles/yfiles'
export class CustomNodeStyle extends NodeStyleBase {
protected createVisual(context: IRenderContext, node: INode): SvgVisual {
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
const { x, y, width, height } = node.layout
rect.setAttribute('x', String(x))
rect.setAttribute('y', String(y))
rect.setAttribute('width', String(width))
rect.setAttribute('height', String(height))
rect.setAttribute('fill', '#0b7189')
return new SvgVisual(rect)
}
}
Recommended Pattern (Typed Cache + updateVisual)
For production implementations, declare a Cache type and a named visual type using TaggedSvgVisual, then pass it as the type argument to NodeStyleBase. This enables typed access to visual.tag in updateVisual and avoids recreating DOM elements on every render frame.
import {
NodeStyleBase,
SvgVisual,
TaggedSvgVisual,
type IRenderContext,
type INode
} from '@yfiles/yfiles'
// 1. Declare the cache shape
type Cache = { width: number; height: number }
// 2. Declare the visual type — ties the SVG element type to the cache type
type CustomNodeStyleVisual = TaggedSvgVisual<SVGPathElement, Cache>
// 3. Pass the visual type as the type argument to NodeStyleBase
export class CustomNodeStyle extends NodeStyleBase<CustomNodeStyleVisual> {
protected createVisual(
context: IRenderContext,
node: INode
): CustomNodeStyleVisual {
const { x, y, width, height } = node.layout
const pathElement = document.createElementNS(
'http://www.w3.org/2000/svg',
'path'
)
// Render at (0,0) and position via transform — required for efficient updates
pathElement.setAttribute('d', createPathData(0, 0, width, height))
SvgVisual.setTranslate(pathElement, x, y)
pathElement.setAttribute('fill', '#0b7189')
pathElement.setAttribute('stroke', '#042d37')
// SvgVisual.from() creates a TaggedSvgVisual with the cache stored in .tag
return SvgVisual.from(pathElement, { width, height })
}
protected updateVisual(
context: IRenderContext,
oldVisual: CustomNodeStyleVisual,
node: INode
): CustomNodeStyleVisual {
const { x, y, width, height } = node.layout
const pathElement = oldVisual.svgElement
const cache = oldVisual.tag // fully typed as Cache
// Only rebuild the path when size actually changed
if (width !== cache.width || height !== cache.height) {
pathElement.setAttribute('d', createPathData(0, 0, width, height))
oldVisual.tag = { width, height }
}
// Always update position via transform
SvgVisual.setTranslate(pathElement, x, y)
return oldVisual
}
}
Core Concepts
- createVisual(): Creates the SVG visual (required)
- updateVisual(): Reuses the existing DOM element, updating only what changed (highly recommended for larger graphs)
- TaggedSvgVisual<TElement, TCache>: Typed wrapper that ties an SVG element type to a cache type via
.tag - SvgVisual.from(element, cache): Convenience factory that creates a
TaggedSvgVisualin one call - Render at origin + translate: Render the shape at
(0,0)and useSvgVisual.setTranslate()for position — only the transform needs updating when a node moves
Implementation Steps
- Declare a
Cachetype with the values needed to detect changes inupdateVisual - Declare a
CustomNodeStyleVisual = TaggedSvgVisual<TElement, Cache>type alias - Extend
NodeStyleBase<CustomNodeStyleVisual> - In
createVisual(): render at(0,0), set translate, returnSvgVisual.from(element, cache) - In
updateVisual(): readoldVisual.tag(typed), update only changed attributes, always update translate
Related Skills
To extend this foundation:
/yfiles-nodestyle-configure— Make styles configurable and data-driven/yfiles-nodestyle-interaction— Add hit testing and edge cropping/yfiles-nodestyle-advanced— Viewport culling and group nodes
Additional Resources
references/examples.md— Complete examples: rectangle, custom path, group container, framework integrationreferences/reference.md— NodeStyleBase/SvgVisual API, SVG patterns, performance tips, common pitfalls