...
{
"Name": "MyDisplay",
"PanelType": "Canvas",
"DisplayMode": "Page",
"Size": "1366 x 728720",
"Elements": [
{
"Type": "Rectangle",
"Left": 100, "Top": 100, "Width": 200, "Height": 150
}
]
}
...
Before writing ANY element, mentally divide the 1366×728 1366×720 canvas into rectangular zones. Each zone represents a process area, equipment group, or information panel.
Standard zone layout for a process overview (1366×7281366×720):
PAGE TITLE (x:0, y:0, w:1366, h:50) ACTION BTNs | ||||||
|---|---|---|---|---|---|---|
| Zone 2 | Zone 2 | Zone 2 | Zone 2 | Zone 2 | Zone 2 |
BOTTOM PANEL: Trend, Alarms, KPIs, or ML Status (h:300+) | ||||||
...
For N process stages on a 1366×728 1366×720 canvas:
Available width = 1366 - 4020 (left/right margin 20px10px each) = 13261346
Available height = 728720 - 50 (title) - 2010 (top margin) = 658760
Zone width = (Available width - (N-1) × 15) / N
Zone height = 320 (for process row)
Zone startY = 60 (below title)
Zone[i].Left = 20 + i × (zoneWidth + 15)
Zone[i].Top = 60
Zone[i].Width = zoneWidth
Zone[i].Height = 320
Bottom panel:
Left = 20, Top = 400, Width = 1326, Height = 658 - 320 - 20 = 318
...
| Panel | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
|
...
Sizing: Symbols are vector-based and scale to any proportional size. Use 40x40 for compact, 80x80 for medium, 120x120 for large — the library default is just a starting point. On Canvas, always use minimum 80×80 for process overview displays (see Step 3 minimum sizes).
...
Dynamics attach runtime behaviors to ANY element. They decouple the visual effect from the data binding, so any property of any control can become live.
...
Typically Navigation is only in Headers displays
For button/navigation behavior:
...
{
"table_type": "DisplaysList",
"data": [{
"Name": "ProcessOverview",
"PanelType": "Canvas",
"DisplayMode": "Page",
"Size": "1366 x 728720",
"Elements": [
{
"Type": "Rectangle",
"Left": 20, "Top": 60, "Width": 208, "Height": 320,
"FillTheme": "PanelBackground",
"Stroke": "#FF909090", "StrokeThickness": 1
},
{
"Type": "TextBlock",
"Text": "Process Overview",
"Left": 20, "Top": 10, "Width": 400, "Height": 35,
"FontSize": 20
}
]
}]
}
...
{
"table_type": "DisplaysList",
"data": [{
"Name": "ControlPage",
"PanelType": "Canvas",
"Size": "1366 x 728720",
"Contents": "CSharp\r\nvoid DisplayOpening()\r\n{\r\n // Initialize display state\r\n}\r\n\r\nvoid ButtonStart_Click(object sender, EventArgs e)\r\n{\r\n @Tag.Plant/Pump1/Command.Value = 1;\r\n}\r\n\r\nvoid ButtonStop_Click(object sender, EventArgs e)\r\n{\r\n @Tag.Plant/Pump1/Command.Value = 0;\r\n}",
"Elements": [
{
"Type": "Button",
"Text": "Start Pump",
"Left": 50, "Top": 100, "Width": 120, "Height": 40,
"ClickEvent": "ButtonStart_Click"
},
{
"Type": "Button",
"Text": "Stop Pump",
"Left": 200, "Top": 100, "Width": 120, "Height": 40,
"ClickEvent": "ButtonStop_Click"
},
{
"Type": "TextBlock",
"LinkedValue": "{@Tag.Plant/Pump1/Running.Value}",
"Left": 50, "Top": 160, "Width": 200, "Height": 25
}
]
}]
}
...
FillTheme: "PanelBackground""Flow: {@Tag.X} GPM")PanelBackground theme RectanglesName (not ObjectName)PanelType is set at top level (never inside JsonFormat)...