Arrow icon
See all demos

SCADA/HMI

Piping and Instrumentation Diagrams (P&IDs) play a crucial role in the design and implementation of Supervisory Control and Data Acquisition (SCADA) and Human-Machine-Interface (HMI) systems, particularly in industrial processes. SCADA/HMI systems are used to monitor and control various aspects of industrial operations, and P&IDs serve as visual representations of the interconnected piping and instrumentation within these processes.
Demo instructions
By interacting with the controls, you can change the stream of data, change the control colors using the toolbar, or simply watch the data flow through the process.

Made with JointJS+

The source code of this demo is available as part of the JointJS+ commercial license. Don't have a license yet? Start a trial and use the source code of this and many other demos for free, with no obligations, for 30 days.

Compatible with:

ReactAngularVueSvelteHTML5Salesforce Lightning

Made with JointJS+

All features required to build this demo are included in the commercial JointJS+ package. Don't have a license yet? Start a trial and build professional applications with ease.

Compatible with:

ReactAngularVueSvelteHTML5Salesforce Lightning

Made with JointJS

The source code of this demo is available in the JointJS open-source library which helps developers create simple visual applications in less time.

Compatible with:

ReactAngularVueSvelteHTML5Salesforce Lightning

Made with JointJS

All features required to build this demo application are included in our open-source library, JointJS. Download the package and create basic visual applications in no time.

Compatible with:

ReactAngularVueSvelteHTML5Salesforce Lightning

What is a SCADA/HMI and how to develop one using JointJS+?

SCADA/HMI systems (Supervisory Control and Data Acquisition/Human-Machine Interfaces), along with P&ID (Piping and Instrumentation Diagram) applications, have become indispensable in modern industries. These systems provide essential functions such as real-time control, data acquisition, and remote monitoring, leading to a revolutionary transformation in industrial automation.

SCADA/HMI systems, used across manufacturing, energy, oil and gas, transportation, and other industries, optimize processes and improve productivity. With P&ID integration, these systems gain precision in control and monitoring complex industrial processes. 

With the assistance of diagramming libraries such as JointJS+, front-end developers can programmatically create intelligent and interactive SCADA/HMI interfaces using JavaScript (or TypeScript), significantly improving the efficiency and precision of the development process. JointJS+ simplifies development, enabling businesses to stay at the forefront by delivering exceptional customer experiences and driving innovation in industrial automation.

JointJS+ offers an extensive array of plugins, features, and customization options, enabling the creation of interactive and dynamic SCADA/HMI interfaces seamlessly integrated into web applications. In this demo application, we have utilized foreign objects which enables us to include HTML elements in our SVG elements, to be specific input elements such as checkboxes, sliders, and buttons.

The SCADA/HMI demo application above is written in plain JavaScript, but can be easily rewritten in TypeScript or integrated with a wide range of web application frameworks such as React, Angular, Vue, Svelte, or Salesforce Lightning. To check its source code, start a free 30-day trial of JointJS+.

Integration

Are you interested in designing SCADA/HMI interfaces using TypeScript or popular JavaScript frameworks like React, Vue, Angular, Svelte, or Salesforce Lightning? With JointJS+, integrating SCADA/HMI becomes seamless as it is a framework-agnostic solution. The SCADA/HMI demo application, along with other JointJS and JointJS+ demos, is designed to be flexible and easily integrated with these frameworks, providing you with a pleasant and smooth development experience.

To get you started on your journey, we have prepared examples for the most popular JavaScript frameworks that demonstrate the seamless integration with JointJS+. In this example we will show you how to leverage already mentioned foreignObject support.

TypeScript SCADA/HMI

Welcome to the TypeScript realm! JointJS and JointJS+ come with extensive type definitions, enhancing the SCADA/HMI development experience. While our SCADA/HMI demo is currently crafted with plain JavaScript, the migration to TypeScript is a breeze, offering you the benefits of type safety and improved code maintainability. This guarantees a seamless and enjoyable development process as you create interactive and robust SCADA/HMI interfaces.

React SCADA/HMI

Leverage the joint capabilities of JointJS+ and React to design visually appealing and interactive SCADA/HMI interfaces. React's component-based architecture and efficient rendering complement JointJS+, streamlining the development process for efficient industrial automation interfaces. As mentioned earlier, below is an example of using the foreign objects in React application.

-- CODE language-js --
import { useEffect, useRef } from 'react';
import { dia, util } from '@clientio/rappid';

class ScadaButton extends dia.Element {
   defaults() {
       return {
           type: 'scada.Button',
           position: {
               x: 0,
               y: 0
           },
           attrs: {
               foreignObject: {
                   width: 'calc(w)',
                   height: 'calc(h)'
               }
           }
       }
   }

   preinitialize(...args) {
       super.preinitialize(...args);

       // To handle events you need to create a custom view for this element
       this.markup = util.svg/* xml */`
           <foreignObject @selector="foreignObject">
               <div
                   xmlns="http://www.w3.org/1999/xhtml"
                   class="outer"
               >
                  <div class="inner">
                      <span>Click this button!</span>
                      <button>Open valve...</button>
                  </div>
               </div>
           </foreignObject>
       `
   }
}

export const ScadaApplication = () => {
   const paperEl = useRef(null);
   const graph = useRef();
   const paper = useRef();

   useEffect(() => {
       const namespace = {
           ScadaButton
       }

       graph.current = new dia.Graph({}, { cellNamespace: namespace });
       paper.current = new dia.Paper({
           model: graph.current,
           el: paperEl.current,
           frozen: true,
           async: true,
           width: 500,
           height: 500,
           cellViewNamespace: namespace
       });

       const buttonEl = new ScadaButton({
           size: {
               width: 150,
               height: 50
           }
       });

       graph.current.addCell(buttonEl)

       paper.current.unfreeze();

       return () => {
           paper.current.remove();
       };
   }, []);

   return (
       <div id= "paper" ref = { paperEl } />
);
}

🔗 Interested in a step-by-step guide on how to integrate JointJS+ with your React application? Follow our tutorial on React and JointJS+ integration. For more examples, check out our Github repository.

Vue SCADA/HMI

With JointJS+'s smooth integration into Vue, you are empowered to effortlessly design user-friendly and interactive SCADA/HMI applications. Vue's declarative syntax and component-based approach make it a perfect match for JointJS+, enabling seamless communication and efficient operations in industrial settings. As mentioned earlier, below you can see an example of leveraging the support of foreign objects in Vue application.

-- CODE language-js --
<script setup>
   import { ref, onMounted, onBeforeUnmount } from 'vue';
   import { dia, util } from '@clientio/rappid';

   class ScadaButton extends dia.Element {
       defaults() {
           return {
               type: 'scada.Button',
               position: {
                   x: 0,
                   y: 0
               },
               attrs: {
                   foreignObject: {
                       width: 'calc(w)',
                       height: 'calc(h)'
                   }
               }
           }
       }

       preinitialize(...args) {
           super.preinitialize(...args);

           // To handle events you need to create a custom view for this element
           this.markup = util.svg/* xml */`
              <foreignObject @selector="foreignObject">
                  <div
                      xmlns="http://www.w3.org/1999/xhtml"
                      class="outer"
                  >
                     <div class="inner">
                         <span>Click this button!</span>
                         <button>Open valve...</button>
                     </div>
                  </div>
              </foreignObject>
           `
       }
   }

   const paperEl = ref(null);

   const namespace = {
       ScadaButton
   }

   const graph = new dia.Graph({}, { cellNamespace: namespace })
   const paper = new dia.Paper({
       model: graph,
       frozen: true,
       async: true,
       width: 500,
       height: 500,
       cellViewNamespace: namespace
   });

   onMounted(() => {
       paperEl.value.appendChild(paper.render().el);

       const buttonEl = new ScadaButton({
           size: {
               width: 150,
               height: 50
           }
       });

       graph.addCell(buttonEl)

       paper.unfreeze();
   });

   onBeforeUnmount(() => {
       paper.remove();
   });
</script>

<template>
   <div ref="paperEl"></div>
</template>

🔗 Interested in a step-by-step guide on how to integrate JointJS+ with your Vue application? Follow our tutorial on Vue and JointJS+ integration. For more examples, check out our Github repository.

Angular SCADA/HMI

Streamline SCADA/HMI development with JointJS+ and Angular, benefiting from Angular's robust data binding and dependency injection features. Create dynamic and data-driven interfaces, providing accurate representations of SCADA/HMI systems for enhanced user experiences. Displayed below is an example of using foreign objects in Angular application.

-- CODE language-js --
import { AfterViewInit, OnInit, Component, ViewChild, OnDestroy } from '@angular/core';
import { dia, util } from '@clientio/rappid';

class ScadaButton extends dia.Element {
   defaults() {
       return {
           type: 'scada.Button',
           position: {
               x: 0,
               y: 0
           },
           attrs: {
               foreignObject: {
                   width: 'calc(w)',
                   height: 'calc(h)'
               }
           }
       }
   }

   preinitialize(...args) {
       super.preinitialize(...args);

       // To handle events you need to create a custom view for this element
       this.markup = util.svg/* xml */`
           <foreignObject @selector="foreignObject">
               <div
                   xmlns="http://www.w3.org/1999/xhtml"
                   class="outer"
               >
                  <div class="inner">
                      <span>Click this button!</span>
                      <button>Open valve...</button>
                  </div>
               </div>
           </foreignObject>
       `
   }
}

@Component({
   selector: 'scada-application',
   template: `
       <div #paperEl></div>
   `
})

export class ScadaApplication implements OnInit, AfterViewInit, OnDestroy {
   @ViewChild('paperEl') paperEl;

   private graph;
   private paper;

   public ngOnInit() {
       const namespace = {
           ScadaButton
       }
       const graph = this.graph = new dia.Graph({}, { cellNamespace: namespace });
       const paper = this.paper = new dia.Paper({
           model: graph,
           frozen: true,
           async: true,
           width: 500,
           height: 500,
           cellViewNamespace: namespace
       });

       paper.render();

       const buttonEl = new ScadaButton({
           size: {
               width: 150,
               height: 50
           }
       });

       graph.addCell(buttonEl)
   }

   public ngAfterViewInit() {
       const { paper, paperEl } = this;
       paperEl.nativeElement.appendChild(this.paper.el);
       paper.unfreeze();
   }

   public ngOnDestroy() {
       const { paper } = this;
       paper.remove();
   }
}

🔗 Interested in a step-by-step guide on how to integrate JointJS+ into your Angular application? Follow our tutorial on Angular and JointJS+ integration. For more examples, check out our Github repository.

Svelte SCADA/HMI

Harness the lightweight and reactive nature of Svelte combined with JointJS+ for visually captivating and responsive SCADA/HMI interfaces. Although a pre-built Svelte demo is not available, our tutorial will guide you through the integration process. Bellow is an example of using foreign objects in Svelte application.

-- CODE language-js --
<script>
import { onMount, onDestroy } from 'svelte';
import { dia, util } from '@clientio/rappid/rappid.js';

class ScadaButton extends dia.Element {
   defaults() {
       return {
           type: 'scada.Button',
           position: {
               x: 0,
               y: 0,
           },
           attrs: {
               foreignObject: {
                   width: 'calc(w)',
                   height: 'calc(h)',
               },
           },
       };
   }

   preinitialize(...args) {
       super.preinitialize(...args);

       // To handle events you need to create a custom view for this element
       this.markup = util.svg/* xml */ `
           <foreignObject @selector="foreignObject">
               <div
                   xmlns="http://www.w3.org/1999/xhtml"
                   class="outer"
               >
                  <div class="inner">
                      <span>Click this button!</span>
                      <button>Open valve...</button>
                  </div>
               </div>
           </foreignObject>
       `;
   }
}

let paperEl;
let graph;
let paper;

onMount(() => {
   const namespace = {
       ScadaButton,
   };

   graph = new dia.Graph({}, { cellNamespace: namespace });
   paper = new dia.Paper({
       model: graph,
       el: paperEl,
       frozen: true,
       async: true,
       width: 500,
       height: 500,
       cellViewNamespace: namespace,
   });

   const buttonEl = new ScadaButton({
       size: {
           width: 150,
           height: 50,
       },
   });

   graph.addCell(buttonEl);
   paper.unfreeze();
});

onDestroy(() => {
   paper.remove();
});
</script>

   < main bind: this = { paperEl } />

🔗 Interested in a step-by-step guide on how to integrate JointJS+ into your Svelte application? Follow our tutorial on Svelte and JointJS+ integration. For more examples, check out our Github repository.

Salesforce Lightning SCADA/HMI

For developers exploring the Salesforce Lightning framework, integrating JointJS+ opens up exciting opportunities in SCADA/HMI development. The exceptional performance and rich feature set of Salesforce Lightning seamlessly combine with JointJS+, empowering developers to create efficient and visually appealing SCADA/HMI interfaces. By leveraging JointJS+'s interactive capabilities in Salesforce Lightning applications, developers can design smart and intuitive interfaces for real-time control, data acquisition, and remote monitoring of industrial processes. This seamless integration ensures businesses can drive efficiency and productivity in various industries, delivering exceptional SCADA/HMI solutions that provide a competitive edge in the market.

🔗 Interested in a step-by-step guide on how to integrate JointJS+ into your Lightning application? Follow our tutorial on Lightning and JointJS+ integration.

Ready to take the next step?

Modern development is not about building everything from scratch. The JointJS team equips you with plenty of ready-to-use features and demo apps that can serve as a boilerplate and radically reduce your development time. Start a free 30-day JointJS+ trial to check their source code and develop your next application with ease and confidence.

Speed up your development with a powerful library