SVG visuals

HyperPBI implements two governed vector components:

  • svg: structured declarative scene graph; preferred
  • svgMarkup: strictly sanitized raw SVG fallback

Use SVG for diagrams, process flows, pictorial marks, schematics, custom gauges, and animated KPI presentation. Use semantic ECharts components for standard analytical charts.

Structured svg

Required properties are viewBox and elements; include ariaLabel. Optional component properties include width/height, preserveAspectRatio, role, description, dataContext, motion, performance, dataset, normal component interaction/UI actions, and shared styling.

Supported elements

g, path, rect, circle, ellipse, line, polyline, polygon, text, tspan, defs, linearGradient, radialGradient, stop, clipPath, mask, marker, title, and desc.

The schema allowlists properties by element family:

  • shapes: coordinates, dimensions, path/points/pathLength
  • text: text/position/anchor/baseline/font properties
  • gradients/stops: endpoints/centers/radius/offset/color/opacity/units/transform/spread
  • groups/defs/clip/mask/marker: marker dimensions/reference/orientation/viewBox/aspect
  • common: safe paint/stroke/opacity/transform/position/reference/pointer/visibility, children, repeat, animation, interaction, and UI action

Unknown element types or properties are errors.

Values and bindings

A value is a literal string/number/Boolean/null or an object using:

  • bind: current-row field, $index, or $count
  • template: direct {{fieldAlias}} and row namespaces {{row.fieldAlias}}, {{item.fieldAlias}}, or {{datum.fieldAlias}}; supported aggregation namespaces such as {{sum.fieldAlias}} are field-bearing, while metric, state, selected, configuration, and runtime namespaces are preserved rather than rewritten
  • scale: linear|threshold|ordinal, domain array or auto, range, optional clamp
  • map: string-keyed value map with fallback
  • when/then/else: field condition using the standard filter operators
  • state/equals/then/else: dashboard-state condition

position resolves numeric x/y/rotate/scale into a safe transform. Literal transforms allow only numeric translate/scale/rotate/skew/matrix functions—no URL/expression content.

Data contexts

  • aggregate (default): sums fields whose non-null values are all finite numbers; otherwise takes the first non-null value
  • selectedRow: uses the first selected row key; falls back to aggregate with a warning
  • first: optionally sorts by sortBy; default direction is descending unless asc; warns when multiple rows are used without a sort field

The component's dataset controls its normal rows. An element repeat may name another dataset.

Repeat semantics

repeat accepts optional dataset, limit, keyField, and required children.

  • default row limit: 100
  • hard row limit: 250
  • nested repeats: not supported (maxRepeatDepth: 1)
  • a missing keyField is allowed but warns because identity may be unstable
  • repeated local IDs are re-namespaced per repeat key
  • interaction against a repeated named dataset maps selected dataset rows through that dataset's lineage to source rows

Interactions

An SVG element may carry the same universal interaction and uiAction as a component. Repeated elements carry their row index/key. Selection trigger state is computed from component-selected source rows. External filter rules remain unchanged: a real model-column field is required; derived fields/metrics cannot directly filter Power BI.

Animations

Presets:

fade-in, slide-in, scale-in, pulse, float, swim, rotate, draw-path, progress-fill, follow-progress, flow-dash, blink-status, bounce, shimmer

Triggers:

auto, hover, focus, selected, dataChange, state, none

state requires stateKey; selected activates only for selected marks; dataChange changes the animation key when the bound row changes. Hover/focus use scoped selectors. none disables animation.

Duration is 100–60,000 ms; delay 0–30,000 ms; finite iterations 1–100. Infinite iteration is allowed only for continuous presets pulse, float, swim, rotate, flow-dash, bounce, and shimmer. Direction is normal|reverse|alternate|alternate-reverse; fill mode is none|forwards|backwards|both. Easing is limited to standard keywords, bounded cubic-bezier, or steps.

Custom keyframes allow only offset plus opacity, transform, fill/stroke properties, stroke dash offset, and x/y/cx/cy/r/width/height. Offset is 0–1.

draw-path is limited to path/line/polyline/polygon. progress-fill is limited to rect/line/path.

Reduced motion and lifecycle

Motion policy is respect-system, always-reduce, or never-reduce. Component/runtime motion may also be disabled. Reduced mode emits no animation and leaves the authored final/static state. Every compiled animation also contains a prefers-reduced-motion guard. Offscreen/inactive SVG blocks pause animations.

The active animation budget is the minimum of component performance, component motion, runtime config (default 12), and the hard limit.

Exact limits

LimitValue
Elements per component500
Elements per dashboard2,000
Animated elements per component20
Animated elements per dashboard50
Default repeat rows100
Maximum repeat rows250
Path d characters20,000
Gradients per component50
Masks per component25
Clip paths per component50
Markers per component50
Nesting depth20
Repeat depth1
Raw SVG markup characters250,000

Performance overrides (maxElements, maxAnimatedElements, maxRepeatedRows) can only lower the corresponding hard limits.

svgMarkup

svgMarkup requires nonempty svg containing one parseable SVG document. Text templates are XML-escaped. Templates cannot create element/attribute names, and a field cannot inject d path data.

The sanitizer:

  • accepts only svg plus the structured element allowlist
  • accepts only the explicit attribute allowlist
  • removes every on*, style, href, xlink:href, src, srcset, and form-action attribute
  • blocks JavaScript/data/blob/HTTP/HTTPS/protocol-relative values
  • rejects duplicate/unsafe IDs, namespaces valid IDs, and rewrites local references
  • removes unknown/malformed local references
  • blocks content deeper than 20 and paths longer than 20,000 characters
  • returns an empty SVG when markup exceeds 500 elements
  • applies a final DOMPurify SVG pass

Explicitly forbidden tags include script, foreignObject, iframe, object, embed, image, use, audio/video/canvas, style, a, switch, set, and discard. SVG filters are disabled in the final profile.

Raw markup does not accept arbitrary CSS. Component css, if used, still passes the scoped CSS sanitizer and may reference only safe local SVG IDs when that mode is enabled.

Minimal example

{
  "type": "svg",
  "id": "completion_gauge",
  "viewBox": "0 0 400 140",
  "height": 140,
  "ariaLabel": "Completion percentage",
  "dataContext": { "mode": "aggregate" },
  "motion": {
    "enabled": true,
    "reducedMotion": "respect-system",
    "maxConcurrentAnimations": 4
  },
  "elements": [
    {
      "type": "rect",
      "id": "track",
      "x": 20,
      "y": 70,
      "width": 360,
      "height": 20,
      "rx": 10,
      "fill": "#e5e7eb"
    },
    {
      "type": "rect",
      "id": "value",
      "x": 20,
      "y": 70,
      "width": {
        "bind": "completionRate",
        "scale": {
          "type": "linear",
          "domain": [0, 1],
          "range": [0, 360],
          "clamp": true
        }
      },
      "height": 20,
      "rx": 10,
      "fill": "#206bc4",
      "animation": {
        "preset": "progress-fill",
        "durationMs": 800
      }
    }
  ]
}