Dynamic SVG Rotation Animation in WinCC Unified HMI

David Krause13 min read
HMI ProgrammingSiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Overview

SIMATIC WinCC Unified supports scalable vector graphics (SVG) natively inside the HMI runtime. Because an SVG graphic is just structured XML rendered by the Chromium-based visualization layer, the same document that displays a static fan blade or pump impeller can be driven by dynamic values, scripts, or by the SVG animation elements themselves. The practical question is which of those three mechanisms to use when the goal is continuous rotation synchronized with the running machine state.

This reference compares the three documented techniques for animating a rotating SVG graphic in WinCC Unified:

  1. A timed JavaScript scheduled from the screen Loaded event.
  2. A dynamization script bound directly to the RotationAngle property, re-triggered by an internal clock.
  3. A native SVG <animateTransform> embedded inside the svghmi widget itself.

The three approaches differ in CPU load on the Unified Runtime, in animation smoothness at low refresh rates, and in authoring complexity. The matrix in the Comparison section below summarizes the trade-offs.

Prerequisites

  • TIA Portal V17 or later (V18 or V19 recommended for current Unified Comfort Panels and Unified PC Runtime). The scripting and svghmi widget improvements referenced in this article are documented in the TIA Portal Help from V17 Update 4 onward; see the SIMATIC WinCC Unified Engineering V19 - Programming and Operating Manual.
  • SIMATIC WinCC Unified Runtime V17 or later on a Unified Comfort Panel (MTP/MTP Unified) or on a WinCC Unified PC station.
  • Project file: an SVG graphic with a transformable group containing the rotating element. The SVG must use a non-zero origin group structure so that RotationAngle rotates around the intended pivot.
  • Optional: the MDN <animateTransform> reference for the native animation method.
  • Basic familiarity with the WinCC Unified screen editor and the JavaScript dialect used by Unified scripting (ECMAScript 2020 compatible).
Important: The WinCC Unified simulation in the TIA Portal browser preview uses a different graphics layer than the real panel or the WinCC Unified PC Runtime. Animations that work in the panel may appear frozen or jerky in the browser preview. Always verify on the actual runtime target.

Method 1 - Timed Script in the Screen Loaded Event

The first approach places a recurring update routine in the Loaded event of the screen that hosts the SVG graphic. The script writes an ever-increasing angle into an internal tag, which is then bound to the RotationAngle property of the SVG via a tag dynamization.

Step 1 - Declare an internal rotation tag

In the HMI tag table, create an internal tag of type Int or Real. Name it for example UI_SVG_RotationDeg. If you want the rotation to survive a screen change, bind it to the global namespace; otherwise keep it as a session-local tag.

Step 2 - Bind RotationAngle to the tag

Select the SVG object on the screen, open Properties > Appearance > Rotation - angle, and add a tag dynamization that writes the value of UI_SVG_RotationDeg directly to RotationAngle. Configure the dynamization as a direct mapping, no script required.

Step 3 - Add the scheduler in the Loaded event

Open the screen Events > Loaded and insert the following JavaScript. The script schedules itself using setInterval, advancing the rotation tag by a fixed increment each tick.

// Screen Loaded event - WinCC Unified JavaScript
// Increment rotation tag every 30 ms (about 33 fps)
let angle = 0;
const step = 6;          // degrees per tick: 6 deg * 33 Hz = 198 deg/s
const periodMs = 30;

const rotationTimer = setInterval(function() {
    angle = (angle + step) % 360;
    HMIRuntime.Tags.SysSet.Set('UI_SVG_RotationDeg', angle);
}, periodMs);

// Stop the timer when the screen unloads
export const onUnload = function() {
    if (rotationTimer) {
        clearInterval(rotationTimer);
    }
};

Trade-offs:

  • Pros: Smooth visual result because the dynamization is tag-driven and renders at the runtime framerate; the script body is simple and decoupled from the SVG content.
  • Cons: Each tick executes a tag write, which costs an internal process-image update. At 30 ms tick on a panel with several rotating graphics this becomes measurable; reduce the tick rate or the step value accordingly.
  • Cons: The Loaded event lives outside the SVG, so the rotation script is not portable when the SVG is reused on another screen.

Tuning the tick interval

Period (ms) Approx fps Visual smoothness Typical CPU cost (Unified Comfort Panel)
50 20 Acceptable for slow shafts, fans, conveyor rollers Low
30 33 Smooth for pumps and impellers Medium
20 50 Smooth for fast propellers, indicator needles Medium-High
10 100 Visually identical to 50 fps; rarely needed High

Method 2 - Script Bound to the RotationAngle Property

Instead of driving a tag from the Loaded event, place the script directly on the RotationAngle property of the SVG object. The dynamization trigger (clock icon) determines how often the script runs.

Step 1 - Open the property dynamization

Select the SVG on the screen, navigate to Properties > Appearance > Rotation - angle, click the dynamization button and choose Script.

Step 2 - Configure the trigger

In the dynamization editor, click the clock icon next to Trigger. Choose Cyclic and set the update interval. 100 ms is the typical starting value for indicators. To approximate continuous rotation use 30-50 ms intervals; the runtime tolerates this on a single rotating object.

Step 3 - Write the script

The script body returns the next rotation angle. Use the runtime helper Tags('UI_SVG_RotationDeg').Read() to retain the last value between triggers.

// RotationAngle dynamization script - cyclic trigger
let current = 0;
try {
    current = Tags('UI_SVG_RotationDeg').Read();
} catch (e) {
    current = 0;
}
current = (current + 6) % 360;
Tags('UI_SVG_RotationDeg').Write(current);
return current;

Trade-offs:

  • Pros: Self-contained - the rotation logic travels with the SVG, not with the screen event. Easier reuse across screens and faceplates.
  • Pros: Shorter script and direct authoring of the animation behavior.
  • Cons: The script runs only when the trigger fires. If the Unified Runtime is busy with other cyclic tasks (alarms, logging, value scaling), the trigger slips and the animation appears jerky. The animation can never be smoother than the slowest frame of the runtime scheduler.
  • Cons: The script executes inside the property evaluation pipeline; long-running logic blocks other property updates on the same object.
Field note: If the rotation graphic must remain smooth during alarm storms or value logging bursts, prefer Method 3 (native SVG animation), which runs on the GPU compositor and is independent of the JavaScript scheduler.

Method 3 - Native SVG <animateTransform> Inside the svghmi Widget

The most efficient approach embeds the animation directly in the SVG file. WinCC Unified renders SVG through the Chromium engine, so SMIL animation elements such as <animate>, <animateTransform> and <animateMotion> are evaluated by the browser layer rather than by the Unified scheduler. The SVG itself becomes a self-contained animation that can also be driven by external values.

Step 1 - Author the SVG

Open the SVG in Inkscape, Adobe Illustrator or a text editor. Wrap the rotating sub-graph in a group with a transform-origin near the desired pivot, then add an <animateTransform> child:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
  <g id="rotor" transform="translate(100 100)">
    <g>
      <path d="M0,0 L0,-80 L20,-60 Z" fill="#0a8fcf"/>
      <circle r="6" fill="#222"/>
      <animateTransform attributeName="transform"
                        type="rotate"
                        from="0"
                        to="360"
                        dur="2s"
                        repeatCount="indefinite"/>
    </g>
  </g>
</svg>

Step 2 - Reference attributes from the Unified side

If you need to start, stop or change the rotation speed based on process state (for example, a fan that only spins when the motor is running), expose the animation attributes as parameters on the SVG <svghmi> widget and bind them in TIA Portal:

<svghmi>
  <svg ...>
    <g id="rotor">
      <path d="..."/>
      <animateTransform attributeName="transform"
                        type="rotate"
                        from="0 100 100"
                        to="360 100 100"
                        dur="{dur}"
                        repeatCount="indefinite"
                        begin="0s; {trigger}.beginEvent"
                        end="{trigger}.endEvent"/>
    </g>
  </svg>
</svghmi>

Bind dur and trigger to internal tags in TIA Portal. The WinCC Unified Engineering manual describes the svghmi widget interface in detail; consult the WinCC Unified Engineering Manual, section Working with SVG graphics.

Step 3 - Center of rotation

SMIL's rotate type uses the geometric center of the group's bounding box by default. To rotate around an arbitrary pivot use the extended form from="0 cx cy" to="360 cx cy", where cx and cy are the pivot coordinates in the SVG user space. This is the same form used in animateMotion; see the MDN <animateTransform> reference for the syntax.

Trade-offs

  • Pros: Highest visual smoothness because the animation is composed on the GPU layer of the Chromium renderer; CPU usage on the panel remains minimal.
  • Pros: Decoupled from JavaScript scheduler and from runtime process-image traffic.
  • Cons: Animating every degree is wasteful: a circle has fourfold rotational symmetry, so a stepped animation of 0, 90, 180, 270 with keyTimes can produce the same visual result with one quarter of the keyframes. The same observation applies to symmetric fan blades and impellers.
  • Cons: Requires authoring the SVG by hand or with a tool that supports SMIL export, since Inkscape's Save As Optimized SVG strips animation unless the SMIL option is preserved.

Comparison of the Three Methods

Criterion Method 1: Loaded event Method 2: Property script Method 3: SVG <animateTransform>
Visual smoothness at 30 ms tick High Medium (depends on runtime load) Very high
CPU load on Unified Comfort Panel Medium (tag write per tick) Low-Medium (no tag write) Very low (GPU compositor)
Reusable across screens No (script lives in screen event) Yes (script is part of the object) Yes (SVG is portable)
Responsive to process state (start/stop) Easy Easy Medium (SMIL begin/end events)
Authoring complexity Low Low Medium-High
Risk of frame jitter during alarm storms Low-Medium High Very low
Browser simulation behavior Works May not work in TIA Portal preview Works in panel, may differ in preview

Choosing the Right Method

  • Use Method 1 when the rotation is part of a larger screen-level script (e.g. several indicators driven by the same setInterval) and you want all animations to share one scheduler.
  • Use Method 2 for a single, low-speed indicator on a screen where you want the script to travel with the object.
  • Use Method 3 when the animation must stay smooth regardless of runtime activity (alarm bursts, recipe loads, value logging), when the SVG is reused on multiple screens or as part of a faceplate library, or when the symbol must also work in offline SVG viewers.

SVG Animation Element Reference

WinCC Unified's Chromium engine supports the SMIL animation elements documented by the W3C. The most relevant subset is summarized below.

Element Purpose Key attributes
<animate> Animate a single numeric attribute over time attributeName, from, to, dur, repeatCount, keyTimes, values
<animateTransform> Animate a transform attribute (rotate, scale, translate, skew) type, from, to, dur, additive
<animateMotion> Move an element along a path path, rotate, keyPoints
<set> Set an attribute at a specific time (no interpolation) attributeName, to, begin, end

For the canonical attribute reference and worked examples see the MDN <animateTransform> documentation and the MDN <animate> documentation. Background on the SVG specification and its support for raster-image animation fallbacks (APNG, MNG) is summarized on the SVG animation Wikipedia page.

Verification Procedure

  1. Compile and download the project to the Unified Comfort Panel or to the Unified PC Runtime.
  2. Start the screen hosting the rotating graphic. Confirm that the symbol begins rotating at the expected speed (e.g. one revolution per 2 s).
  3. Trigger an alarm burst by forcing a batch of 20-50 alarms. The animation should remain at the same framerate when Method 3 is used.
  4. Open the runtime diagnostics via the WinCC Unified system diagnostics page and confirm that JavaScript CPU time stays below 5 percent during normal operation with Method 3, and below 20 percent with Method 1 at 30 ms tick.
  5. Test on the actual target, not only in the TIA Portal browser preview. The preview uses a different rendering path and may misrepresent SMIL animation behavior on some browser versions.
  6. Switch the project to a different screen and back. Verify that the animation restarts cleanly. With Method 3, this is automatic; with Method 1, confirm that the Unload handler cleared the interval.

Troubleshooting Matrix

Symptom Likely cause Resolution
Static graphic in browser preview, rotates correctly on panel TIA Portal preview Chromium build handles SMIL differently from the panel runtime Verify on the actual runtime; do not rely on the preview as acceptance gate
Graphic stutters every few seconds Method 2 trigger interval is being skipped by the runtime scheduler Reduce trigger interval to 30 ms or migrate to Method 3
Graphic rotates too fast after screen change Method 1 setInterval was not cleared on unload, and a new timer was started Add clearInterval in the screen Unload event
Rotation only goes 0-90 degrees then jumps SVG group has a non-zero transform attribute and SMIL rotation is composing incorrectly Wrap the rotating geometry in a clean group with transform="translate(cx cy)" and rotate inside that group
Animation not visible after import Inkscape export stripped SMIL elements Re-export with Save As > Plain SVG and verify the <animate*> tags are present in the XML
CPU spikes above 30 percent during rotation Method 1 tick is too aggressive or too many rotating objects share the same scheduler Raise tick to 50 ms, reduce step, or migrate to Method 3
SVG RotationAngle dynamization ignored Property is locked because a tag dynamization is already attached Remove the tag dynamization first, then add the script dynamization
Center of rotation off-screen Method 3 rotate type without center coordinates uses the bounding-box center, which may be wrong for non-symmetric groups Use the extended from="0 cx cy" to="360 cx cy" form with explicit pivot

Performance and Safety Considerations

Continuous rotation is a visual cue, not a measurement. The goal is operator perception that the machine is running, not a frame-perfect animation. For most rotating indicators, an effective frame rate of 20-25 Hz is indistinguishable from 60 Hz to a human operator. Spending CPU budget on a faster rotation is rarely justified.

On a Unified Comfort Panel (MTP2200, MTP1900, MTP1500), Method 1 at a 30 ms tick produces approximately 8-12 percent additional JavaScript CPU load per rotating graphic. Method 3 produces negligible CPU load. If the panel already runs heavy logging or alarm handling, prefer Method 3.

For animations that change dynamically based on process state (a fan that speeds up when motor current increases), use Method 3 with multiple SMIL <animateTransform> elements switched by begin/end events, or by binding the dur attribute to a HMI tag through the svghmi widget's parameter interface.

Safety note: A rotating graphic must never be the only indication that a machine is running. Always provide an explicit, static status indicator (motor contactor feedback, speedometer tag, or color-coded state field) so that the operator can confirm the running state even when the animation fails or is hidden behind a pop-up.

FAQ

Which method gives the smoothest SVG rotation in WinCC Unified?

Native SVG <animateTransform> embedded inside the svghmi widget (Method 3) gives the smoothest result because the animation runs on the Chromium GPU compositor, independent of the Unified JavaScript scheduler and immune to runtime load spikes.

Why does my rotating SVG work on the panel but not in the TIA Portal browser preview?

The TIA Portal preview uses a different Chromium build than the Unified Runtime on the panel. Some preview builds disable SMIL animation or render it at a lower framerate. Always verify dynamic SVG behavior on the actual Unified Comfort Panel or Unified PC Runtime, not in the preview.

What tick interval should I use for the property script in Method 2?

Start at 100 ms for slow indicators (tank level dial, conveyor roller). For pump impellers and fast fans use 30-50 ms. Below 20 ms the runtime scheduler is unlikely to honor the trigger consistently and the animation becomes jerky; in that case migrate to Method 3.

How do I rotate an SVG around a point that is not the geometric center?

Use the extended rotate syntax in <animateTransform>: from="0 cx cy" to="360 cx cy", where cx and cy are the pivot coordinates in SVG user space. The same form is described in the MDN <animateTransform> reference.

Can I drive the rotation speed from a HMI tag?

Yes. With Method 3 expose the SMIL dur attribute as a parameter on the svghmi widget and bind it to a real tag (for example motor speed in RPM, scaled to seconds per revolution). With Method 1 or 2 use the tag value to compute the step increment in the script.

Back to blog