SCADAvis.io

The Ultimate Web Visualization Solution

Create stunning web-based HMI/SCADA-like applications with a powerful SVG visualization library. Perfect for real-time monitoring systems.

↓

Key Features

↓

Demo

2.5D Office Visualization


        
scadavisInit({
  container: "div1",
  iframeparams: 'frameborder="0" height="490" width="555"',
  svgurl: "https://raw.githubusercontent.com/riclolsen/displayfiles/master/office2.svg"
  }).then( sv => {
    sv.zoomTo(0.65);
    setInterval(function () {
      sv.storeValue("TAG1", Math.random() * 100);
      sv.storeValue("TAG2", 100 + Math.random() * 80);
      sv.storeValue("TAG3", 120 + Math.random() * 60);
      sv.storeValue("TAG4", 150 + Math.random() * 60);
      sv.storeValue("TAG5", 110 + Math.random() * 30);
      sv.storeValue("TAG6", 200 + Math.random() * 100);
      sv.storeValue("TAG7", 130 + Math.random() * 40);
      sv.updateValues();
    }, 1000);
  })
          
      
↓

Demo

Interactive Substation Simulation


        
  scadavisInit({
    container: "subst-demo",
    iframeparams: 'frameborder="0" height="390" width="680"',
    svgurl:
        "https://raw.githubusercontent.com/riclolsen/displayfiles/master/kor1-v2.svg",
    }).then((sv) => {
    sv.zoomTo(0.42);
    sv.enableTools(true);
    sv.storeValue(
        "KOR1TR1--YTAP",
        Math.round(8 + Math.random()),
        false,
        false
    );
    sv.storeValue("KOR1XSWI1", false);
    sv.storeValue("KOR1XSWI2", true);
    sv.storeValue("KOR1XSWI4", true);
    sv.storeValue("KOR1XSWI6", true);
    sv.storeValue("KOR1XSWI8", true);
    sv.storeValue("KOR1XSWI10", false);
    sv.storeValue("KOR1XSWI12", true);
    sv.storeValue("KOR1XSWI14", true);
    sv.storeValue("KOR1XSWI16", false);
    sv.storeValue("KOR1XSWI18", true);
    sv.storeValue("KOR1XSWI20", true);
    sv.storeValue("KOR1XSWI22", false);
    sv.storeValue("KOR1XSWI48", true);
    sv.storeValue("KOR1XSWI50", true);
    sv.storeValue("KOR1XSWI46", false);
    sv.storeValue("KOR1XSWI24", true);
    sv.storeValue("KOR1XSWI26", true);
    sv.storeValue("KOR1XSWI28", false);
    sv.storeValue("KOR1XSWI30", true);
    sv.storeValue("KOR1XSWI32", true);
    sv.storeValue("KOR1XSWI34", true);
    sv.storeValue("KOR1XSWI36", true);
    sv.storeValue("KOR1XSWI38", false);
    sv.storeValue("KOR1XSWI40", true);
    sv.storeValue("KOR1XSWI42", true);
    sv.storeValue("KOR1XSWI44", false);
    sv.storeValue("KOR1XCBR2", true);
    sv.storeValue("KOR1XCBR3", true);
    sv.storeValue("KOR1XCBR4", true);
    sv.storeValue("KOR1XCBR8", true);
    sv.storeValue("KOR1XCBR5", true);
    sv.storeValue("KOR1XCBR2401", false);
    sv.storeValue("KOR1XCBR6", true);
    sv.storeValue("KOR1AL11TC", true, false, false);
    sv.storeValue("KOR1AL11RREC", true, false, false);
    sv.storeValue("KOR1AL11PSTI", true, false, false);
    sv.storeValue("KOR1AL12TC", true, false, false);
    sv.storeValue("KOR1AL12RREC", true, false, false);
    sv.storeValue("KOR1AL12PSTI", true, false, false);
    sv.storeValue("KOR1AL13TC", true, false, false);
    sv.storeValue("KOR1AL13RREC", true, false, false);
    sv.storeValue("KOR1AL13PSTI", true, false, false);
    sv.storeValue("KOR1AL14RREC", true, false, false);
    sv.storeValue("KOR1AL14PSTI", true, false, false);
    sv.storeValue("KOR1AL15TC", true, false, false);
    sv.storeValue("KOR1AL15PSTI", true, false, false);
    sv.storeValue("KOR1AL16TC", true, false, false);
    sv.storeValue("KOR1AL16PSTI", true, false, false);
    sv.storeValue("KOR1AL17TC", true, false, false);
    sv.storeValue("KOR1AL17RREC", true, false, false);
    sv.storeValue("KOR1ALTFTC", true, false, false);
    sv.storeValue("KOR1ALTFRREC", true, false, false);
    sv.storeValue("KOR1ALTFPSTI", true, false, false);
    sv.storeValue("KOR1AL11MW", 0, false, false);
    sv.storeValue("KOR1AL12MW", 0, false, false);
    sv.storeValue("KOR1AL13MW", 0, false, false);
    sv.storeValue("KOR1AL14MW", 0, false, false);
    sv.storeValue("KOR1AL15MW", 0, false, false);
    sv.storeValue("KOR1AL16MW", 0, false, false);
    sv.storeValue("KOR1AL17MW", 0, false, false);

    function updateSubstation() {
        let xcbr1 = Math.random() > 0.2 ? true : false;
        sv.storeValue("KOR1TR1-2XCBR5201", xcbr1, false, !xcbr1);
        let kv230 = 220 + Math.random() * 20;
        let kv23 =
        (kv230 / 10.3) *
        xcbr1 *
        Math.sqrt(sv.getValue("KOR1TR1--YTAP") / 7);
        sv.storeValue("KOR1KV230", kv230, false, kv230 > 239 || kv230 < 221);
        sv.storeValue("KOR1KV23", kv23, false, kv23 > 23.9 || kv23 < 22.1);

        let xcbr7 = Math.random() > 0.15 ? true : false;
        sv.storeValue("KOR1XCBR7", xcbr7, false, !xcbr7);
        sv.storeValue(
        "KOR1AL14TC",
        Math.random() > 0.15 ? true : false,
        false,
        false
        );
        sv.storeValue(
        "KOR1AL15RREC",
        Math.random() > 0.15 ? true : false,
        false,
        false
        );
        sv.storeValue(
        "KOR1AL16RREC",
        true,
        Math.random() > 0.15 ? true : false,
        false
        );
        sv.storeValue(
        "KOR1AL17PSTI",
        true,
        false,
        Math.random() > 0.15 ? true : false
        );

        let MW = 0,
        tMW = 0;
        let MVAR = 0,
        tMVAR = 0;
        tMW += MW = (5 + Math.random() * 2) * xcbr1 * xcbr7;
        tMVAR += MVAR = (0.5 - Math.random() * 1) * xcbr1 * xcbr7;
        sv.storeValue("KOR1AL11MW", MW, false, false);
        sv.storeValue("KOR1AL11MVAR", MVAR, false, false);
        tMW += MW = (3 + Math.random() * 2) * xcbr1;
        tMVAR += MVAR = (0.5 - Math.random() * 1) * xcbr1;
        sv.storeValue("KOR1AL12MW", MW, false, false);
        sv.storeValue("KOR1AL12MVAR", MVAR, false, false);
        tMW += MW = (6 + Math.random() * 2) * xcbr1;
        tMVAR += MVAR = (0.5 - Math.random() * 1) * xcbr1;
        sv.storeValue("KOR1AL13MW", MW, false, false);
        sv.storeValue("KOR1AL13MVAR", MVAR, false, false);
        tMW += MW = (4 + Math.random() * 2) * xcbr1;
        tMVAR += MVAR = (0.5 - Math.random() * 1) * xcbr1;
        sv.storeValue("KOR1AL14MW", MW, false, false);
        sv.storeValue("KOR1AL14MVAR", MVAR, false, false);
        tMW += MW = (5 + Math.random() * 2) * xcbr1;
        tMVAR += MVAR = (0.5 - Math.random() * 1) * xcbr1;
        sv.storeValue("KOR1AL15MW", MW, false, false);
        sv.storeValue("KOR1AL15MVAR", MVAR, false, false);
        tMW += MW = (3 + Math.random() * 2) * xcbr1;
        tMVAR += MVAR = (0.5 - Math.random() * 1) * xcbr1;
        sv.storeValue("KOR1AL16MW", MW, false, false);
        sv.storeValue("KOR1AL16MVAR", MVAR, false, false);
        tMW += MW = (5 + Math.random() * 2) * xcbr1;
        tMVAR += MVAR = (0.5 - Math.random() * 1) * xcbr1;
        sv.storeValue("KOR1AL17MW", MW, false, false);
        sv.storeValue("KOR1AL17MVAR", MVAR, false, false);
        tMW += MW = (4 + Math.random() * 2) * xcbr1;
        tMVAR += MVAR = (0.5 - Math.random() * 1) * xcbr1;
        sv.storeValue("KOR1ALTFMW", 0, false, false);
        sv.storeValue("KOR1ALTFMVAR", 0, false, false);

        sv.storeValue("KOR1TR1MW", tMW, false, false);
        sv.storeValue("KOR1TR1MVAR", tMVAR, false, false);

        sv.updateValues();
    }
    setInterval(updateSubstation, 2333);
    updateSubstation();

    sv.on("click", function (event, tag) {
        var v = sv.getValue(tag);

        if (event.currentTarget.id === "TAPUP") {
        sv.setValue(tag, v + 1, false, false);
        return;
        } else if (event.currentTarget.id === "TAPDOWN") {
        sv.setValue(tag, v - 1, false, false);
        return;
        }

        if (event.currentTarget.id === "XCBROPEN") {
        sv.setValue(tag, false, false, false);
        return;
        } else if (event.currentTarget.id === "XCBRCLOSE") {
        sv.setValue(tag, true, false, false);
        return;
        }

        if (v === true) sv.setValue(tag, false, false, false);
        else if (v === false) sv.setValue(tag, true, false, false);
    });
    });
          
      
↓

How It Works

Simple Integration in Three Steps

🎨

1. Design

Create high-quality vector graphics with the Inkscape-based SVG editor. Animate SVG properties linking to your data using tags. Animate fill/stroke colors, text, rotation, size, position, add interactivity and much more.

<>

2. Embed

Embed the Javascript Synoptic API into your web pages. It provides a sandboxed iframe that doesn’t interfere with your frontend environment.

✨

3. Showtime

Pass the SVG file and tagged data in real time using the API. Watch your visualization come to life with smooth animations and real-time updates.

Workflow Diagram
↓

Powerful Integrations

Connect with your favorite tools

Grafana

Integrate SCADAvis.io visualizations directly into your Grafana dashboards. Use Grafana's powerful data sources and combine them with our interactive SVG visualizations.

  • βœ“ Native Grafana Panel Plugin
  • βœ“ Real-time Data Integration
  • βœ“ Compatible with all Grafana Data Sources
Learn More β†’

Node-RED

Create dynamic visualizations in Node-RED flows. Perfect for IoT applications and industrial automation projects that need real-time visual feedback.

  • βœ“ Integrates with UI-Builder Package
  • βœ“ Easy Data Mapping
Learn More β†’

MQTT

Connect your MQTT broker via web sockets to SCADAvis.io visualizations. Ideal for IoT devices and real-time monitoring systems.

  • βœ“ MQTT Protocol Support
  • βœ“ Sparkplug-B Support
  • βœ“ Topic Subscribe/Publish
  • βœ“ Secure Connection (TLS)
Learn More β†’
↓

Professional SVG Editor

Create stunning visualizations with our powerful built-in editor, based on the industry-standard Inkscape.

Inkscape has been modified to allow for markup of data-linked animations directly in the SVG file. Available only for Windows 10/11 computers on the Microsoft Store. Out-of-store version of the editor costs US$ 129.99 per user (request license here [email protected]).

SCADAvis.io SVG Editor Interface
↓

Toolkit Pricing

The SCADAvis.io Web Toolkit is free to use online or self-hosted. Paying customers have access to support and advanced options.

Free

$0 forever
  • βœ“ Unlimited usage
  • βœ“ Data privacy
  • βœ“ Open source
  • βœ“ Self-hosted or online
  • βœ“ Rolling release cycle
  • βœ“ Best for professionals, startups, and evaluation
Get Started

Enterprise

$899 yearly
  • βœ“ Everything in Free
  • βœ“ E-mail support
  • βœ“ 5-year LTS versions
  • βœ“ Best for large companies
Contact Us