SVG widget
SvgView renders static SVG documents through the 2d context:
geometry becomes Path2D objects, <g transform="…"> becomes context
transforms, paint servers become canvas gradients — so everything is
composited server-side by XRender like any other 2d drawing.
import { createClient, SvgView } from 'ntk';
const app = await createClient();
const wnd = app.createWindow({ width: 480, height: 360, title: 'svg' });
const view = new SvgView(wnd);
view.setSvg(await readFile('drawing.svg', 'utf8'));
wnd.map();
Standalone (windowless) use mirrors HtmlView/MarkdownView — draw into
any 2d context (a window, a pixmap):
const view = new SvgView(null);
view.setSvg(svgText);
view.draw(ctx, x, y, width, height);
See examples/svg-viewer.js for a small viewer
(node svg-viewer.js file.svg).
HtmlView uses this widget for SVG inside HTML documents: inline
<svg> elements and <img> sources that sniff as SVG (files, buffers,
data:image/svg+xml URIs) are laid out like images and drawn through
SvgView.
API
new SvgView(window[, opts])—windowmay benullfor standalone use. Options:theme.background— window-mode background fill (default'white')fit— window-mode fitting:'contain'(default; fitted + centered, preserving aspect ratio) or'fill'(stretch)
view.setSvg(svgText)— parse and adopt a document (a string containing an<svg>element). Re-renders in window modeview.setSvgDom(element)— adopt an already-parsed htmlparser2<svg>element. Used by HtmlView for inline SVG; tolerates HTML-mode parses (lowercased tag/attribute names likeviewbox,lineargradient)view.draw(ctx, x, y[, w, h])— draw into any 2d context;w/hdefault to the natural size. TheviewBox(when present) is scaled to the target boxview.render()— window mode: clear the background and draw fitted; called automatically onexposeview.naturalWidth/view.naturalHeight— from thewidth/heightattributes, falling back to theviewBoxsizeview.viewBox—[minX, minY, width, height]ornull
Like HtmlView, the widget is static and safe by construction: no
scripting, no network or filesystem access — documents are strings and
nothing external is ever fetched.
Supported SVG subset
Elements:
- shapes:
path(full path-data grammar, arcs included),rect(+rx/ry),circle,ellipse,line,polyline,polygon - structure:
svg(viewBox,width/height),g,defs,use(href/xlink:hrefto a local#id,x/yoffset,symboltargets),a(rendered, not clickable) - paint servers:
linearGradient,radialGradientwithstop(offset,stop-color,stop-opacity),gradientUnitsofobjectBoundingBox(default) oruserSpaceOnUse text— basic:x,y,font-size,font-family,text-anchor, solidfill; rendered through the shaped-text pipeline
Presentation attributes (also inside inline style="…", which wins):
fill,stroke— colors,none,currentColor,url(#gradient)fill-rule(nonzero/evenodd),fill-opacity,stroke-opacity,opacity(multiplies down the tree)stroke-width,stroke-linecap,stroke-linejoin,stroke-miterlimittransform—matrix,translate,scale,rotate(incl. the 3-argument center form),skewX,skewY, in any list combinationcolor(forcurrentColor)
Not supported (skipped silently): CSS stylesheets/<style>, clipPath,
mask, filter, pattern, marker, animation/SMIL, foreignObject,
external references, preserveAspectRatio values other than the default
behavior, stroke dashing, and full text layout (tspan, textPath).
SVG path data elsewhere
The path-data parser is shared with Path2D and exported directly:
import { Path2D, parseSvgPath } from 'ntk';
ctx.fill(new Path2D('M10 10 A 20 20 0 0 1 50 10 Z'));
const commands = parseSvgPath('M0 0 Q 5 5 10 0'); // [{type:'M',…}, {type:'Q',…}]
parseSvgPath returns normalized M/L/C/Q/Z commands (arcs are converted
to cubics) — the same shape consumed by lib/rasterize.js and the TeX
widget.