Implementing Custom Graphic Elements in a SCADA Configuration System
Adding a New Sidebar Menu Category
To introduce a new category in the left-hand sidebar, modify the Sidebar.js file. Locate the Sidebar.prototype.categoryMenus array and add a new object. For example, to add a 'Control Components' category:
Sidebar.prototype.categoryMenus = [
// ... existing categories
{
id: 4,
name: 'Control Components',
defaultSrc: mxUtils.staticImg('/rcscada/menu/ic_menu_control_default.svg'),
checkedSrc: mxUtils.staticImg('/rcscada/menu/ic_menu_control_check.svg'),
checked: false,
funcNames: ['addCustomStateImagePalette'],
},
];
name: The display name for the menu category.defaultSrc: Path to the icon displayed when the category is not selected.checkedSrc: Path to the icon displayed when the category is selected.funcNames: An array containing the names of methods responsible for populating the category's palette groups. These methods must be defined onSidebar.prototype.
To prevent the main Sidebar.js file from becoming too large, it's recommended to define these palette-adding methods in separate modules. For instance, define addCustomStateImagePalette in a file like CustomExpands.js and import it into Sidebar.js:
// In Sidebar.js
import { CustomExpands } from './sidebar/CustomExpands';
Defining Palette Groups and Elements
Creating a Palette Group
Edit the CustomExpands.js file (or your designated module) to define the method specified in funcNames. This method creates and returns an array of graphic element template functions.
Sidebar.prototype.addCustomStateImagePalette = function () {
const elementTemplates = [];
// Example 1: Toggle Switch
const closedIcon = `/rcscada/images/usr/switch/1.svg`;
const openIcon = `/rcscada/images/usr/switch/2.svg`;
let styleString = `shape=mxgraph.rc.mxRc_stateSwitch;readonly=1;rcDprop=openCloseValues;igDprop=commonStrokeColor;openStateImg=${openIcon};closeStateImg=${closedIcon};html=1;shadow=0;dashed=0;strokeWidth=1;stateValue=0;title=Toggle Switch;opacity=100;fillColor=none;${mxConstants.STYLE_VERTICAL_LABEL_POSITION}=bottom;${mxConstants.STYLE_VERTICAL_ALIGN}=top;`;
elementTemplates.push(this.createVertexTemplateEntry(styleString, 150, 150, '', 'Toggle Switch', true, '', '', mxUtils.staticImg(closedIcon), ''));
// Example 2: State Image
const defaultImage = `/rcscada/images/usr/light/1.png`;
styleString = `shape=mxgraph.rc.mxRc_stateImage;readonly=1;igDprop=commonStrokeColor;rcSprop=defaultImg;rcDprop=stateImageValues;defaultImg=${defaultImage};stateImage=;html=1;shadow=0;dashed=0;strokeWidth=1;stateValue=0;title=State Image;opacity=100;fillColor=none;${mxConstants.STYLE_VERTICAL_LABEL_POSITION}=bottom;${mxConstants.STYLE_VERTICAL_ALIGN}=top;`;
elementTemplates.push(this.createVertexTemplateEntry(styleString, 150, 150, '', 'State Image', true, '', '', mxUtils.staticImg(defaultImage), ''));
// Example 3: Flow Line (Edge)
const flowIcon = `/rcscada/menu/ic_menu_pip_flow.gif`;
elementTemplates.push(this.createEdgeTemplateEntry(
'endArrow=none;html=1;endArrow=none;endFill=0;enableFlow=1;strokeWidth=10;strokeColor=#28E8D8;pipWidth=13;pipDash=10;strokeBgColor=#312727;flowDirection=1;',
200, 200, '', 'Flow Line', null, null, null, true, mxUtils.staticImg(flowIcon), ''));
// Add more element definitions here...
// Register the palette group with its elements
this.addPaletteFunctions('mxRc_stateSwitch', 'Variable Controls', true, elementTemplates);
};
The addPaletteFunctions method registers the group. Its parameters are:
- A unique identifier for the palette.
- The display title for the group.
- A boolean indicating if the group should be expanded by default.
- The array of template functions (
elementTemplates).
Understanding Element Definition
Each element is defined by pushing a template creation function into the array. For vertex elements, use createVertexTemplateEntry. For connection lines/edges, use createEdgeTemplateEntry.
Key parameters for createVertexTemplateEntry:
- Style String: A semicolon-separated list of properties defining the element's appearance and behavior.
- Width & Height: Initial dimensions (e.g.,
150, 150). - Label: Text displayed on the element in the palette (often empty).
- Tooltip: Name shown when hovering over the element in the palette (e.g.,
'Toggle Switch'). - Icon: The preview image for the palette, created with
mxUtils.staticImg(path).
The most critical property in the style string is shape. It points to the rendering class for the element (e.g., shape=mxgraph.rc.mxRc_stateSwitch).
Linking Elements to Rendering Classes
The Rendering Class
The value of the shape property corrresponds to a JavaScript class responsible for drawing the element. For mxgraph.rc.mxRc_stateSwitch, the class is defined in a file like mxRc_stateSwitch.js. This class must define a constant identifying its shape name:
// In mxRc_stateSwitch.js
mxRc_stateSwitch.prototype.cst = {
SHAPE_NAME: 'mxgraph.rc.mxRc_stateSwitch',
};
The core rendering logic is implemented in the paintVertexShape (for vertices) or paintEdgeShape (for edges) method of this class.
mxRc_stateSwitch.prototype.paintVertexShape = function (canvas, x, y, width, height) {
// Custom drawing logic using the canvas API
// ...
};
Registration
All custom shape classes must be registered with the renderer. This is typically done in a central registration file, such as ShapesExpands.js:
// In ShapesExpands.js
import mxRc_stateSwitch from './shapes/mxRc_stateSwitch';
// ... import other shape classes
mxCellRenderer.registerShape(mxRc_stateSwitch.prototype.cst.SHAPE_NAME, mxRc_stateSwitch);
// ... register other shapes
This registration links the shape property value from the style string to the corresponding JavaScript class, enabling the system to instantiate the correct renderer when the element is used.