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+.
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.
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.
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.
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.
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.
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.
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.
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.