Yfiles Nodestyle Basic
Scannednpx machina-cli add skill yWorks/yfiles-for-html-claude-plugin/yfiles-nodestyle-basic --openclawBasic 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
Source
git clone https://github.com/yWorks/yfiles-for-html-claude-plugin/blob/main/skills/yfiles-nodestyle-basic/SKILL.mdView on GitHub Overview
Yfiles Nodestyle Basic shows how to build custom node visuals by extending NodeStyleBase and rendering with SVG. It covers both a simple, no-cache approach for prototyping and a recommended typed cache pattern using TaggedSvgVisual for production performance. The skill explains createVisual and updateVisual responsibilities and how to leverage visual caching.
How This Skill Works
Developers override createVisual in a subclass of NodeStyleBase to render an SVG element for a node. For production, declare a Cache shape and a CustomNodeStyleVisual type using TaggedSvgVisual, then implement updateVisual to reuse DOM when only layout data changes, updating transforms and attributes as needed.
When to Use It
- When you need a fully custom node rendering (SVG) beyond default styles
- When implementing a NodeStyleBase-based style for createVisual and updateVisual
- When you want a minimal prototype with no caching
- When you need typed access to the cached visual via .tag
- When you want to optimize rendering by reusing DOM elements and transforms
Quick Start
- Step 1: Import NodeStyleBase and SvgVisual, create a class CustomNodeStyle extends NodeStyleBase, implement createVisual to render an SVG element
- Step 2: For production, declare a Cache type and a CustomNodeStyleVisual using TaggedSvgVisual, and implement updateVisual to reuse the DOM
- Step 3: Apply the style to your graph and observe how visuals are positioned via transforms and updated efficiently
Best Practices
- Start with a minimal createVisual to prototype, then add caching for production
- Use a Typed Cache and TaggedSvgVisual to store dimensions and state for updateVisual
- Render content at (0,0) and position via SvgVisual.setTranslate for efficient updates
- Only rebuild path or geometry in updateVisual when size or layout actually changes
- Avoid recreating DOM elements on every render frame to maximize performance
Example Use Cases
- A simple CustomNodeStyle that draws a filled rectangle for each node
- A path-based node using a cached SVG element and transform positioning
- Typed cache pattern with CustomNodeStyleVisual to access .tag in updateVisual
- updateVisual that updates transforms and attributes without DOM recreation
- Prototype example with no caching to rapidly test visuals