Demo URL: http://121.40.16.189:12000
1. Adding a New Widget Category to the Sidebar
1.1. Registering the Menu Entry
To add a new category (e.g., "Control Widgets") to the left sidebar, modify Sidebar.js. Locate the Sidebar.prototype.categoryMenus array and insert a new entry:
Sidebar.prototype.categoryMenus = [
{
id: 4,
name: 'Control Widgets',
defaultSrc: mxUtils.staticImg('/rcscada/menu/ic_menu_control_default.svg'),
checkedSrc: mxUtils.staticImg('/rcscada/menu/ic_menu_control_check.svg'),
checked: false,
funcNames: ['addCustomStateImagePalette'],
},
];
The funcNames array references methods attached to Sidebar.prototype. To avoid bloating Sidebar.js, these methods can be defined in external files like CustomExpands.js and imported:
import { CustomExpands } from './sidebar/CustomExpands';
1.2. Defining Widget Groups
In CustomExpands.js, implement the referenced method (e.g., addCustomStateImagePalette) to register individual widgets:
Sidebar.prototype.addCustomStateImagePalette = function () {
const templates = [];
// Toggle Switch
const closedIcon = `/rcscada/images/usr/switch/1.svg`;
const openIcon = `/rcscada/images/usr/switch/2.svg`;
let style = `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;`;
templates.push(this.createVertexTemplateEntry(style, 150, 150, '', 'Toggle Switch', true, null, null, mxUtils.staticImg(closedIcon)));
// State Image
let imgPath = `/rcscada/images/usr/light/1.png`;
style = `shape=mxgraph.rc.mxRc_stateImage;readonly=1;igDprop=commonStrokeColor;rcSprop=defaultImg;rcDprop=stateImageValues;defaultImg=${imgPath};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;`;
templates.push(this.createVertexTemplateEntry(style, 150, 150, '', 'State Image', true, null, null, mxUtils.staticImg(imgPath)));
// Dynamic Text
imgPath = `/rcscada/menu/ic_menu_text.svg`;
style = 'text;rcDprop=stateTextValues;readonly=1;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;';
templates.push(this.createVertexTemplateEntry(style, 200, 100, 'Text', 'Dynamic Text', true, null, null, mxUtils.staticImg(imgPath)));
// Flow Indicator (Edge)
imgPath = `/rcscada/menu/ic_menu_pip_flow.gif`;
templates.push(this.createEdgeTemplateEntry(
'endArrow=none;html=1;enableFlow=1;strokeWidth=10;strokeColor=#28E8D8;pipWidth=13;pipDash=10;strokeBgColor=#312727;flowDirection=1;',
200, 200, '', 'Flow Bar', null, null, null, true, mxUtils.staticImg(imgPath)
));
// Liquid Tank
imgPath = `/rcscada/menu/ic_menu_trough.svg`;
style = `shape=mxgraph.rc.mxRc_squareTrough;igDprop=commonStrokeColor;rcDprop=troughLiquidProgressValues;rcSprop=troughMinScale,troughMaxScale,troughBorderWidth,troughBorderRadius,troughBorderColor,troughBackgroundColor,troughLiquidColor;troughMinScale=0;troughMaxScale=100;troughBorderWidth=5;troughBorderRadius=5;troughBorderColor=#000000;troughBackgroundColor=#FFFFFF;troughLiquidColor=#00AAFF;html=1;shadow=0;dashed=0;strokeWidth=1;stateValue=0;title=Liquid Tank;opacity=100;fillColor=none;${mxConstants.STYLE_VERTICAL_LABEL_POSITION}=bottom;${mxConstants.STYLE_VERTICAL_ALIGN}=top;`;
templates.push(this.createVertexTemplateEntry(style, 200, 200, '', 'Liquid Tank', true, null, null, mxUtils.staticImg(imgPath)));
// Digital Clock
imgPath = `/rcscada/menu/ic_menu_shuzi_time.svg`;
style = `shape=mxgraph.rc.mxRc_shu_zi_time;rcDprop=shuziTimeValues;showFontStyle=1;readonly=1;timeFormat=0;igDprop=commonStrokeColor;rcSprop=timeFormat;html=1;shadow=0;dashed=0;strokeWidth=1;stateValue=0;title=Digital Clock;opacity=100;fillColor=none;${mxConstants.STYLE_VERTICAL_LABEL_POSITION}=bottom;${mxConstants.STYLE_VERTICAL_ALIGN}=middle;`;
templates.push(this.createVertexTemplateEntry(style, 180, 180, '', 'Digital Clock', true, null, null, mxUtils.staticImg(imgPath)));
// Video Player
imgPath = `/rcscada/menu/ic_menu_video_play.svg`;
style = `shape=mxgraph.rc.mxRc_video_play;rcDprop=videoPlayerValues;readonly=1;igDprop=commonStrokeColor,commonFontColor;html=1;shadow=0;dashed=0;strokeWidth=0;title=Video Player;opacity=100;fillColor=none;${mxConstants.STYLE_VERTICAL_LABEL_POSITION}=bottom;${mxConstants.STYLE_VERTICAL_ALIGN}=top;`;
templates.push(this.createVertexTemplateEntry(style, 200, 120, '', 'Video Player', true, null, null, mxUtils.staticImg(imgPath)));
// Thermometer
imgPath = `/rcscada/menu/ic_menu_thermometer.png`;
style = `shape=mxgraph.rc.mxRc_thermometer;readonly=1;rcDprop=scaleValValues;rcSprop=showScale,bgFillColor1,bgFillColor2,minScale,maxScale,smallUnitScale,bigUnitScale,scaleValDuration,scaleTransX,scaleFontSize,scaleColor,scaleFontColor;scaleTransX=0.0;scaleColor=#528CFF;bgFillColor1=#F8D7D1;bgFillColor2=#FF5D3C;igDprop=commonStrokeColor,commonFontColor;html=1;shadow=0;dashed=0;showScale=1;scaleValDuration=1.0;minScale=0;maxScale=100;smallUnitScale=2;bigUnitScale=20;strokeWidth=1;strokeColor=#528CFF;fontColor=#528CFF;fontSize=12;title=Thermometer;opacity=100;fillColor=none;aspect=fixed;${mxConstants.STYLE_VERTICAL_LABEL_POSITION}=bottom;${mxConstants.STYLE_VERTICAL_ALIGN}=top;`;
templates.push(this.createVertexTemplateEntry(style, 120, 200, '', 'Thermometer', true, null, null, mxUtils.staticImg(imgPath)));
// Gauge Meter
imgPath = `/rcscada/menu/ic_menu_rcgauge1.png`;
style = `shape=mxgraph.rc.mxRc_gauge1;readonly=1;rcDprop=scaleValValues;rcSprop=showScale,bgFillColor1,bgFillColor2,minScale,maxScale,smallUnitScale,bigUnitScale,scaleValDuration,scaleTransX,scaleFontSize,scaleColor,scaleFontColor;perimeterSpacing=40;scaleTransX=0.0;scaleColor=#528CFF;bgFillColor1=#F8D7D1;bgFillColor2=#FF5D3C;igDprop=commonStrokeColor,commonFontColor;html=1;shadow=0;dashed=0;showScale=1;scaleValDuration=1.0;minScale=0;maxScale=100;smallUnitScale=2;bigUnitScale=20;strokeWidth=1;strokeColor=#528CFF;fontColor=#528CFF;fontSize=12;title=Gauge Meter;opacity=100;fillColor=none;${mxConstants.STYLE_VERTICAL_LABEL_POSITION}=bottom;${mxConstants.STYLE_VERTICAL_ALIGN}=top;`;
templates.push(this.createVertexTemplateEntry(style, 150, 200, '', 'Gauge Meter', true, null, null, mxUtils.staticImg(imgPath)));
// Text Input
imgPath = `/rcscada/menu/ic_menu_htmlInput.png`;
style = `shape=mxgraph.rc.mxRc_htmlInput;showFontStyle=1;placeholderText=Input here;readonly=1;rcDprop=htmlTextInputDefaultValues;igDprop=commonStrokeColor,commonFontColor;html=1;shadow=0;dashed=0;strokeWidth=1;strokeColor=#528CFF;fontColor=#333;fontSize=12;title=Text Input;fillColor=none;${mxConstants.STYLE_VERTICAL_LABEL_POSITION}=bottom;${mxConstants.STYLE_VERTICAL_ALIGN}=top;`;
templates.push(this.createVertexTemplateEntry(style, 200, 60, '', 'Text Input', true, null, null, mxUtils.staticImg(imgPath)));
// Text Area
imgPath = `/rcscada/menu/ic_menu_htmlTextArea.png`;
style = `shape=mxgraph.rc.mxRc_htmlTextarea;showFontStyle=1;placeholderText=Input here;textAreaRows=4;readonly=1;rcDprop=htmlTextareaDefaultValues;igDprop=commonStrokeColor,commonFontColor;html=1;shadow=0;dashed=0;strokeWidth=1;strokeColor=#528CFF;fontColor=#333;fontSize=12;title=Text Area;fillColor=none;${mxConstants.STYLE_VERTICAL_LABEL_POSITION}=bottom;${mxConstants.STYLE_VERTICAL_ALIGN}=top;`;
templates.push(this.createVertexTemplateEntry(style, 300, 120, '', 'Text Area', true, null, null, mxUtils.staticImg(imgPath)));
this.addPaletteFunctions('mxRc_stateSwitch', 'Variable Controls', true, templates);
};
2. Implementing Custom Widgets
2.1. Widget Registration
Widgets are added via addPaletteFunctions, which internally uses createVertexTemplateEntry or createEdgeTemplateEntry. Each entry defines:
- Style string with shape identifier and properties
- Initial dimnesions (width, height)
- Display name and preview icon
2.2. Shape Rendering Class
Each widget references a shape class (e.g., mxgraph.rc.mxRc_stateSwitch). This name must match the SHAPE_NAME constant in the corresponding renderer class (mxRc_stateSwitch.js):
mxRc_stateSwitch.prototype.cst = {
SHAPE_NAME: 'mxgraph.rc.mxRc_stateSwitch',
};
All custom shapes are registered in ShapesExpands.js:
mxCellRenderer.registerShape(mxRc_stateSwitch.prototype.cst.SHAPE_NAME, mxRc_stateSwitch);
2.3. Custom Rendering Logic
Rendering logic resides in the paintVertexShape method of the shape class:
mxRc_stateSwitch.prototype.paintVertexShape = function(canvas, x, y, width, height) {
// Custom drawing implementation
};