Editable dashboard graphics
Цей контент ще не доступний вашою мовою.
A drawing is an equipment diagram inside a dashboard: a pumping station, a single-line diagram, a room layout. It is made of shapes, text, images, lines, and equipment symbols. Their properties, such as a tank’s level, a pump’s running state, or a line’s color, can follow live parameter values, and objects can open details or send commands when an operator selects them.
A drawing is stored as a versioned JSON document in the dashboard’s configuration. The browser
editor, the assistant, workspace source pushed with hmi push, and the graphics API all edit that
same document, so a generated layout can be corrected in the browser without editing dashboard
source. The Canvas dashboard template starts with an empty drawing on a 10-unit grid. For the
steps to draw a diagram, see Draw an equipment diagram.
Drawings in a dashboard
Section titled “Drawings in a dashboard”DashboardGraphics from @overvis/hmi-workspace-ui displays one drawing. It takes workspaceId,
dashboardId, and a UUID drawingId. The optional defaultDocument supplies a drawing before its
first save; a saved drawing takes precedence. Several components can share a dashboard when each
has its own drawing ID. Changing the workspace, dashboard, or drawing ID opens a new session; a
draft or pending action is never carried over to another drawing.
The document is stored at dashboard.configuration.graphics[drawingId]. Each element, connector,
and slot has a UUID.
The drawing displays like an interactive image. viewBox: { x, y, width, height } on the document
sets its fixed frame and aspect ratio; without it, the frame is derived from the saved geometry.
Live readings, including bound size and rotation changes, do not change the frame.
- On desktops the viewer scales the frame to the available width, without a grid or pan and zoom
controls. Optional
maxWidthandmaxHeightprops limit the displayed drawing in pixels while preserving its aspect ratio, for examplemaxWidth={1000} maxHeight={640}for a compact schematic on a large monitor. The limits apply only in view mode. - On phones, tablets, and windows narrower than 1024 px, a drawing that would become too small to read opens at a legible minimum scale instead, starting from its top-left corner. Dragging pans, pinching or the zoom buttons zoom, and the fit button shows the whole drawing.
- Full screen above the drawing shows it over the whole content area, with the same gestures, until Exit full screen or Escape.
Drawings are light-only. In the dark theme the page around the drawing turns dark, while the drawing, its in-drawing controls, and the dialogs it opens keep the light theme.
Drawing model
Section titled “Drawing model”Version 2 supports rectangles, rounded rectangles, ellipses, text, polygons, junctions, images, groups, symbols, and lines. A circle is an ellipse with equal dimensions. Equipment and rooms can be composed from these elements without special prefabs. Only this document version is accepted.
- Element
xandyare absolute drawing coordinates, also for grouped elements.widthandheightare unrotated dimensions, androtationis in degrees about the element center. - Symbol placements may set
mirrorXandmirrorYtotrue; mirroring applies in the symbol’s own frame before rotation. - Shape
pointsuse normalized coordinates between 0 and 1 inside the element’s rectangle. - Groups identify their children through
parentId; moving a group moves its descendants and the bends of lines inside it. lockedprevents moving and resizing an element. Its ports stay available for connections.- A shape’s, image’s, or line’s text is drawn in its stroke color; only a text object uses its fill color for text.
Shapes and lines share one back-to-front order. Their optional integer layer places lower values
behind higher values. Objects without a layer follow those with one, in element order, then line
order. Copies and inserted symbols appear above existing objects.
Lines are stored in connectors. Each from and to end is either a free { x, y } point or an
attachment { elementId, port }: a shape’s left, right, top, or bottom port, a junction’s
center, or a symbol’s named port. route is orthogonal (the default), straight, or curve.
bends are absolute coordinates, and arrow adds an arrowhead. Optional parentId puts a line in
a group, and locked prevents moving it. A line that ends on another line joins it through a
junction; lines that merely cross are not connected. An electrical busbar or distribution trunk is
drawn with ordinary lines and junctions.
graphicsDocumentType from @overvis/hmi-shared/graphics is the TypeBox shape of a document, and
graphicsDocumentSchema validates the shape and the graph rules: unique IDs, existing line ends
and slots, valid groups, one binding per property, and valid input ranges. It also bounds geometry
and array sizes. graphicsConfigurationIssues(configuration) checks the whole graphics map of a
dashboard configuration, including drawing UUIDs, without changing it.
Localized text
Section titled “Localized text”Text that viewers read can be a plain string or one text per locale. This applies to the drawing
title; the text of shapes, text objects, images, and lines; the prefix and suffix of text
format bindings; command label and toggle onLabel and offLabel; and symbol properties
declared as display text, such as the built-in symbols’ label. A locale map has two-letter
lowercase keys and non-empty values:
{ "en": "01 / SOURCE", "pl": "01 / ŹRÓDŁO", "de": "01 / QUELLE" }A plain string reads the same in every language. Command values, slot names, and element names are always plain strings.
Inside a dashboard, a drawing shows the dashboard’s language: the UI language when the dashboard’s
supportedLocales lists it, otherwise English. A map without that language falls back to English,
then to the first locale in alphabetical order that has text. Spaces and line breaks are kept, so a
suffix such as " kW" keeps its leading space.
Localized text is written in code: in the drawing JSON, through hmi push, or by the assistant.
The editor shows each localized field in the drawing’s language, and editing it stores the typed
plain text in place of all its translations.
Element names label objects for authors in the editor. Viewers’ tooltips and screen-reader labels use the object’s text or the symbol’s label instead.
Minimal document
Section titled “Minimal document”This document contains one tank rectangle whose fill level follows a named slot. The slot has no
parameter yet; with a workspace parameter UUID in its parameterId, the tank shows the live level.
{ "version": 2, "title": "Tank", "background": "#ffffff", "grid": 10, "viewBox": { "x": 80, "y": 80, "width": 160, "height": 220 }, "elements": [ { "id": "4c71fa0d-9fc7-4bb3-8103-4adebd6be852", "kind": "rectangle", "name": "Tank", "x": 100, "y": 100, "width": 120, "height": 180, "rotation": 0, "parentId": null, "locked": false, "appearance": { "fill": "#38bdf8", "stroke": "#334155", "strokeWidth": 2, "opacity": 1, "text": "", "fontSize": 16, "fillLevel": 1, "visible": true, "animated": false }, "bindings": [ { "property": "fillLevel", "kind": "scale", "source": { "kind": "slot", "slotId": "a732f598-b685-45b5-b788-df3421f4807f" }, "inputMin": 0, "inputMax": 100, "outputMin": 0, "outputMax": 1 } ], "action": null } ], "connectors": [], "slots": [ { "id": "a732f598-b685-45b5-b788-df3421f4807f", "name": "Level", "parameterId": null } ]}Bindings and data quality
Section titled “Bindings and data quality”Each visual property has at most one binding, and each binding reads exactly one parameter. A
source is either { "kind": "parameter", "parameterId": "<uuid>" } or a named slot. A slot is a
named parameter assignment that several bindings share: assigning a parameter to the slot rebinds
all of them at once. Logic that combines several readings needs a
calculated parameter.
Bindings can format text with precision, prefix, and suffix; scale a numeric input range to width, height, rotation, fill level, or opacity; map thresholds to fill or stroke colors; and apply conditions to visibility or animation. Different properties of one object can use different parameters. The bindable properties follow the object’s artwork:
| Object | Bindable properties |
|---|---|
| Shapes and groups | Text, fill and stroke colors, width, height, rotation, fill level, opacity, visibility, animation |
| Text | Text, fill color, width, height, rotation, opacity, visibility |
| Image | Label text and its stroke color, width, height, rotation, opacity, visibility |
| Line | Text, stroke color, opacity, visibility, animation |
| Symbol | Width, height, rotation, opacity, visibility; the symbol’s own properties use their property bindings |
Unavailable data is not zero. A drawing distinguishes unknown, stale, and failed readings:
- An object keeps its last appearance with a quality indication, and animations pause while readings are not current. Selecting a quality badge shows the parameter diagnostics.
- An object whose visibility is bound to an unavailable reading is hidden, so missing data never shows a status label or an alarm. A stale reading keeps the visibility it last produced.
- A symbol resolves quality per property. An unavailable reading shows ”—”, and an unavailable operating state shows Unknown and stops the animation it drives; the outline, label, and other readings stay visible. A stale value keeps its last value in a stale style.
- A binding whose slot has no parameter counts as unavailable. A symbol property with an explicit
value, or left at its default, counts as current. When equipment has no running, fault, or flow
signal, bind that property through a slot without a parameter instead of setting
falseor0, so the drawing shows it as unknown until a signal is assigned. - An equipment alarm is a parameter value, separate from communication quality.
Actions
Section titled “Actions”Decorative objects do not respond to clicks. An object’s action can open parameter details,
history, a value-edit dialog, or another dashboard. In view mode, selecting a symbol without an
action or named controls opens its details, so every piece of equipment answers alike; one without
live data says it is not connected to live data.
The details dialog is titled with the symbol’s label or the object’s name. Each bound property is a row under the symbol’s own name for it: states by their names (“Open”, “Running”), conditions as Yes or No, and readings with the binding’s precision and the parameter’s units. Readings show when they were read, and a stale one how long ago. Open history opens a temporary report of the object’s parameters. The value-edit dialog shows the current value with units and the parameter’s allowed range, such as “Allowed: 5 bar to 8 bar”, and refuses a value outside it.
Viewers can inspect; operators can perform permitted parameter writes; editors, admins, and owners can edit drawings. Parameter-write permissions apply when an action is invoked from a drawing, and editing a drawing disables equipment writes.
A dashboard action opens another dashboard, or a page of one. Its optional path, search, and
hash address a page, query, or panel within the target dashboard, as in
{ kind: "dashboard", dashboardId, path: "/stations/<stationId>", hash: "pump-<pumpId>" }.
Omitting all three opens the dashboard root. An action within the drawing’s own dashboard that sets
no search keeps the current query, so a page opened from an overview returns to the same filters.
Paths start with / and stay beneath the dashboard; see
dashboard subpages.
Editor
Section titled “Editor”Editing targets desktops. Edit drawing in the bar above the drawing opens the editor. The
toolbar holds undo and redo, arrange (group, ungroup, bring to front, send to back), rotate and
flip, duplicate and delete, and the insert tools: Symbols, the Line tool with its route,
shapes, junction, and image. Each tooltip names its shortcut, and Keyboard shortcuts (or ?)
lists every shortcut and pointer gesture. Scrolling or dragging the background pans; Ctrl+scroll or
a pinch zooms. Panning, zooming, and fitting in the editor choose the frame saved for viewers.
While editing, live binding effects pause, so an object cannot hide or resize itself while it is selected; a bound reading shows ”—” with its units instead of a value. Save returns to the live drawing. Cancel with unsaved changes, or leaving the page, asks first: Discard changes drops the draft and Keep editing returns to it. When Save finds an invalid value, a message names the object and field, and Properties selects the field.
Properties
Section titled “Properties”Properties shows the settings of the selected object. For a symbol, they come in the order of configuration: name, symbol type, label, Variant, Key properties, and Readings and states, then the collapsed Placement (position, size, orientation, mirroring, and lock), Appearance, and Advanced bindings, then the click action. Shapes, text, images, junctions, and groups show their name, Appearance, Placement, and click action, with only the settings their artwork uses. With several objects selected, Properties shows the settings they share; a setting whose values differ shows as mixed, and a change applies to every selected object.
A property that can follow a parameter has a link button beside its label. Linking replaces the value with a binding card that shows the parameter with its type, last reading, and unit, or No parameter assigned. Choosing a parameter assigns it to the binding’s slot, so every binding using that slot follows; Shared slot names the slot and offers No shared slot and New slot for this binding. Remove binding restores the value. Unbound key properties are marked Not bound. Parameter assignments lists every slot with its parameter and how many bindings use it. Use default returns a changed symbol property to the symbol’s default.
With the Line tool (L), drag from a port or anywhere on the drawing to draw a line; the tool stays on until Escape. The route buttons beside it choose Right angle, Straight, or Curved. A new line takes the color and width of the line it branches from, or of the most recent similar line. An orthogonal line without bends is routed automatically: it leaves and enters each port in the direction the port faces and goes around equipment when it must. Dragging a segment or adding a bend saves the route as bends. Double-clicking a line adds a bend, and double-clicking a bend removes it. Dropping a line end on another line branches it with a junction.
Selecting and arranging
Section titled “Selecting and arranging”- Shift, Control, or Command adds objects to the selection; Shift+drag on the background selects everything inside the box.
- Duplicate (Ctrl+D, or Command+D on macOS) copies the selection, with the lines between copied objects, one grid step clear of the originals.
- Objects snap to the drawing grid while they are moved and resized; hold Alt (Option on macOS) to place them freely. Values typed in Properties apply exactly.
- Rotate counter-clockwise and Rotate clockwise (Shift+R and R), Flip horizontally and Flip vertically (Shift+H and Shift+V) act on each selected object in place. Symbols turn in 90° steps.
- Delete (Delete or Backspace) removes the selection, with the lines attached to deleted equipment. Deleting a junction keeps its lines.
Symbol library
Section titled “Symbol library”Symbols opens the library: equipment categories on the left, with Favorites and Recent above them, and search, an industry filter, and the All, Built-in, or Workspace source above the thumbnails. Search matches names, IDs, descriptions, variants, and keywords, including translated synonyms, abbreviations such as VFD, and instrument tags such as PT, LT, or FT. Pipes, tees, and junctions are not symbols: draw them with the Line and Junction tools.
Selecting a tile shows its details: a preview, its purpose, variants, live properties with the essential ones marked, connection points, and state examples. Insert takes the chosen variant; a click on the drawing places it, and R, Shift+R, Shift+H, and Shift+V turn and mirror it first. With Place multiple on, each click adds another copy until Done or Escape. Placing needs no bindings; they are set afterward in Properties. The star on a tile marks a favorite. Favorites and recent symbols are kept in this browser for the signed-in user.
Symbols
Section titled “Symbols”A symbol is one piece of equipment in the drawing. Selecting, moving, resizing, and rotating act on
the whole symbol; its artwork has no separately selectable parts. A symbol declares its own
properties, such as a pump’s running and fault or a reservoir’s level, and decides how those
values change its artwork. It also declares named ports for lines and, optionally, named controls.
A placement uses kind: "symbol", symbolId, properties for explicit values, and
propertyBindings for properties that follow parameters. It keeps the common element geometry,
appearance, bindings, and action fields; actions holds its named controls. Property names
must be unique within each list. Omitted properties use the symbol’s current defaults, and explicit
values survive symbol updates. A missing symbol or one that fails to render shows a placeholder.
Built-in symbol conventions
Section titled “Built-in symbol conventions”- Bind each reading to the property for its quantity, even when another property sits where the
number should appear. A flowmeter’s
flowis a rate that also points its arrow, so a volume counter goes tototal. When a built-in layout cannot place a reading, use a text object bound to the parameter or your own symbol. - Symbols show the states and readings they are given; they never calculate them. A hopper does not derive its inventory from its level, and a weighbridge does not derive net weight from gross and tare.
- Bind each symbol’s essential properties, listed under Key properties, so it shows its operating state. An optional reading that is neither bound nor set is left out rather than shown as a default.
- Alarms and faults come from the flags bound to them; a symbol does not raise an alarm because a reading crosses a limit.
- State choices, such as a valve’s
open,closed,moving, andunknown, take a states binding that maps the controller’s codes to them. - Equipment that runs animates only on fresh feedback, stops on stale or unavailable data, and respects the browser’s reduced-motion preference.
- Ports have stable names, roles (
process,air,electrical,signal, ormaterial), and directions. Mirroring keeps port names, so an inlet stays the inlet. Equipment of one family puts its main ports at a common height, so a row placed on one line connects with straight lines. - Every symbol takes an optional
labelfor its equipment tag, such as P-01 or QF1.
Catalog
Section titled “Catalog”Built-in symbol IDs start with hmi.. The library’s details, or graphics.symbols.get, list each
symbol’s properties, units, ports, and examples.
| Application | Symbols and variants |
|---|---|
| Controls | hmi.button |
| Pumping | hmi.pump (centrifugal), hmi.submersible-pump, hmi.inline-pump |
| Water storage | hmi.tank with open, closed, horizontal, and conical bodies; hmi.well, hmi.reservoir |
| Valves | hmi.shutoff-valve with ball, gate, and butterfly bodies; hmi.solenoid-valve, hmi.modulating-valve, hmi.three-way-valve, hmi.check-valve, hmi.pressure-reducing-valve |
| Water instruments | hmi.water-filter, hmi.flowmeter, hmi.pressure-instrument, hmi.level-instrument |
| Electrical | hmi.ac-supply, hmi.lamp, hmi.motor, hmi.refrigeration-load, hmi.circuit-breaker |
| Power and metering | hmi.electricity-meter, hmi.electricity-meter-compact, hmi.three-phase-panel, hmi.disconnector, hmi.contactor, hmi.earthing-switch, hmi.fuse, hmi.transformer, hmi.generator, hmi.automatic-transfer-switch, hmi.variable-frequency-drive, hmi.solar-array, hmi.solar-inverter, hmi.ups, hmi.battery-storage with rack and bank variants, hmi.capacitor-bank |
| Hydronic heating | hmi.boiler, hmi.burner, hmi.heat-exchanger, hmi.heat-pump, hmi.hot-water-tank, hmi.radiator, hmi.expansion-vessel |
| Air handling | hmi.fan, hmi.damper, hmi.air-filter, hmi.air-coil, hmi.heat-recovery, hmi.humidity-unit, hmi.chiller, hmi.cooling-tower, hmi.air-terminal, hmi.fan-coil |
| Thermal instruments and controls | hmi.heat-meter, hmi.environment-sensor, hmi.temperature-probe, hmi.temperature-controller, hmi.thermal-zone |
| Warehouses and cold storage | hmi.rack, hmi.pallet with tote and container, hmi.door with sliding, roller shutter, and sectional, hmi.loading-dock, hmi.stacker-crane with vertical lift, hmi.agv with forklift, hmi.storage-zone, hmi.cold-room with freezer, hmi.cooling-unit |
| Manufacturing | hmi.conveyor with belt and roller bodies; hmi.machine, hmi.robot-cell, hmi.inspection-station, hmi.cylinder (pneumatic, hydraulic, electric), hmi.agitator (top-entry, side-entry, submersible), hmi.presence-sensor (photoelectric, proximity), hmi.stack-light |
| Compressed air | hmi.air-compressor with screw and piston bodies; hmi.air-receiver, vertical or horizontal; hmi.air-dryer, refrigerated or desiccant; hmi.line-filter with particulate, coalescing, and activated carbon elements; hmi.pressure-reducing-valve as the regulator |
| Thermal processing | hmi.heater with element and bank (1–6 stages) variants; hmi.furnace with oven and furnace variants; hmi.kiln with rotary and tunnel variants |
| Fuel and gas | hmi.gas-detector; hmi.tank with its leak alarm, hmi.flowmeter with its gas-meter body, hmi.pressure-reducing-valve as a gas regulator, and hmi.burner |
| Food and beverage | hmi.process-vessel with jacketed vessel and fermenter variants; hmi.filling-station with bottle and can variants |
| Quarries | hmi.hopper (hopper, silo); hmi.stockpile (conical, elongated); hmi.feeder (vibrating, apron); hmi.crusher (jaw, cone, impact); hmi.screen (single, double, triple deck); hmi.trommel; hmi.belt-scale; hmi.chute; hmi.diverter-gate; hmi.dust-collector (baghouse, cartridge); hmi.spray-suppression (spray bar, fog cannon); hmi.conveyor and hmi.weighbridge |
| Waste and recycling | hmi.waste-container (wheelie bin, skip, underground); hmi.compactor (stationary, self-contained); hmi.baler (horizontal, vertical); hmi.shredder (single-shaft, twin-shaft); hmi.separator (magnetic, optical); hmi.collection-vehicle (rear loader, side loader); hmi.weighbridge |
| Water treatment | hmi.dosing-pump with diaphragm and peristaltic heads; hmi.dosing-unit as a chemical skid or gas chlorinator; hmi.uv-disinfection; hmi.aerator with surface and brush rotors; hmi.diffuser; hmi.clarifier, circular or rectangular; the submersible hmi.agitator for flocculation and hmi.fan as an aeration blower |
| Irrigation and agriculture | hmi.irrigation-zone; hmi.sprinkler with rotor, spray head, and drip emitter variants; hmi.fertigation-unit; hmi.soil-sensor; the well, pumps, water filter, flowmeter, pressure instrument, valves, dosing pump, and tank are also listed under Agriculture |
Variants
Section titled “Variants”For a placed symbol, Variant offers the symbol’s own variants, such as the ball, gate, or butterfly body of a shutoff valve, and other symbols of the same family with the same connection points and properties, such as a solenoid valve. Switching keeps the object’s position, orientation, bindings, and connections. A change that needs other connection points or behavior, such as a two-way valve becoming a three-way valve, needs a new symbol in its place.
Size, orientation, and grid
Section titled “Size, orientation, and grid”Built-in equipment keeps every port on the drawing grid through rotation, flipping, and resizing when the grid spacing is 1, 2, 5, or 10. Pumps, valves, motors, and meters keep their proportions; tanks, wells, reservoirs, doors, zones, and similar equipment stretch in width and height, and conveyors in width. Placement offers Orientation in 90° steps, Mirrored horizontally, and Mirrored vertically. Labels and readings stay upright when a symbol is turned.
Opening a drawing or editing a property or binding never moves equipment. When a symbol’s position, size, or angle is off the grid, Properties lists each value with the one Align to grid would apply, such as “X 233 → 230”, and Align to grid applies them.
Save through the API
Section titled “Save through the API”graphics.get returns { document, revision }; revision is null when no drawing is saved.
graphics.save takes that value as expectedRevision and changes one drawing, keeping the rest of
the dashboard configuration:
const scope = { workspaceId, dashboardId, drawingId };const current = await client.graphics.get.query(scope);const result = graphicsDocumentSchema["~standard"].validate(candidate);if (result.issues) throw new Error("Invalid drawing");await client.graphics.save.mutate({ ...scope, document: result.value, expectedRevision: current.revision,});A save whose expectedRevision is not the current revision fails with graphics_conflict; the
steps to resolve it are in
Draw an equipment diagram.
Live readings do not change revisions. A graphics save also changes the dashboard’s revision, so a
later hmi push of that dashboard from a checkout that did not pull it fails with push_conflict.
A dashboard.update that replaces the configuration must include expectedConfiguration from the
read it was based on, and fails with dashboard_configuration_conflict when the configuration has
changed since.
Symbol validation
Section titled “Symbol validation”graphics.save checks every placement of a built-in symbol against the catalog: the symbol ID,
property names and values, the ports lines attach to, rotation in 90° steps, and, on drawings whose
grid is 1, 2, 5, or 10, a size and corner that keep the ports on the grid. Placements of workspace
symbols are not checked. A property value may be a locale map only when the property is
localized.
Objects added or changed since the saved drawing produce errors, and unchanged objects produce
warnings, so an existing drawing never blocks a save. Off-grid placement and rotation are errors
only in changes the assistant makes; in a person’s edits they are warnings. Errors reject the save
with graphics_invalid_document and details.issues; a successful save returns its warnings in
issues. graphics.validate takes the same input without expectedRevision and returns
{ issues } without saving. hmi push runs the same checks and fails with
push_validation_failed, listing the issues with their drawingId in details.graphicsIssues.
Each issue has severity (error or warning), code, elementId, and symbolId, plus the
fields that locate and repair it:
code | Meaning | Repair fields |
|---|---|---|
unknown_symbol | No built-in symbol has this hmi. ID | — |
unknown_property | An override or property binding names no property | property, allowed (property names) |
invalid_property_value | A property override breaks the property schema | property, schema, allowed (choices) |
unknown_port | A line attaches to a port the symbol lacks | connectorId, port, allowed (ports) |
off_grid_port | A port is not on the drawing grid | port, expected (aligned port point) |
off_grid_position | The placement’s corner is not on the grid | expected (aligned corner) |
invalid_size | The size puts ports off the grid | expected (width, height) |
invalid_rotation | Rotation is not a multiple of 90 degrees | expected (nearest rotation) |
Find symbols
Section titled “Find symbols”graphics.symbols.search (optional text, category, industry, and locale) returns a compact
list of built-in symbols, and graphics.symbols.get returns full details for chosen IDs: variants,
each property’s stored-value schema with its display label and choice labels, units, essential
properties, localized: true on display-text properties, ports with their role and direction,
dimensions, grid metadata, named controls, and examples. Text is in the requested locale. Workspace
symbols are not listed; their definitions are in the workspace source.
Workspace symbols
Section titled “Workspace symbols”A workspace symbol is a .tsx file under src/symbols/, including subdirectories, whose default
export is a defineGraphicsSymbol definition. The workspace dashboard build finds these files and
includes them in every dashboard, without per-dashboard imports, and they are published with the
rest of the workspace source. A component change updates every placement on dashboard reload
without rewriting drawings. IDs must be unique, and IDs starting with hmi. are reserved for
built-in symbols; a dashboard that exports one fails to load. The steps to write one are in
Author a workspace symbol.
import Type, { type Static } from "typebox";import { defineGraphicsSymbol } from "@overvis/hmi-workspace-ui";
const properties = Type.Object( { running: Type.Boolean({ title: "Running", default: false }), }, { additionalProperties: false },);
function Motor({ running }: Static<typeof properties>) { return ( <svg className="size-full" viewBox="0 0 120 80"> <rect x="10" y="10" width="100" height="60" rx="8" fill="#cbd5e1" /> <circle cx="90" cy="30" r="8" fill={running ? "#22c55e" : "#64748b"} /> </svg> );}
export default defineGraphicsSymbol({ id: "my-workspace.motor", name: () => "Motor", width: 120, height: 80, stretch: false, ports: [{ id: "shaft", x: 1, y: 0.5 }], properties: () => properties, Component: Motor,});Components return ordinary React content, including their own <svg> root and viewBox for SVG
artwork. Clip, gradient, and mask IDs are shared by every placement on the page unless they are
unique per component, such as from useId. Components keep local state through property updates,
resizing, and switching between viewing and editing. While editing, the host makes their contents
inert and the whole symbol stays selectable. Workspace source is executable dashboard code with the
same permissions and trust model as other dashboard components.
Renaming or removing a property or port is a breaking change: existing placements keep their data, and the incompatibilities stay visible for repair. Existing placements of a symbol ID render whatever definition currently has that ID.
Properties
Section titled “Properties”The property schema is a closed TypeBox object with a valid default for every property. Supported
fields are numbers, integers, booleans, strings, and unions of string literals. title labels the
field or a literal choice without changing its stored value. Numeric bounds constrain inputs and
clamp bound values. graphicsColor: true on a hex-color string shows a color picker.
graphicsText: true on a string marks text that viewers read: a placement may then store one text
per locale, and the component receives the text in the drawing’s language. A state union that
includes an unknown literal receives it when the state input is unavailable.
Property bindings read one parameter each. Besides the shape binding forms (scale, condition, formatted text, color thresholds), symbols accept:
{ kind: "value", digits? }passes a numeric reading through unchanged;digitssets the readout precision.{ kind: "states", states: [{ value, state }] }maps parameter values (numbers or booleans) to the state IDs of a string-literal union. Unmapped values show as unknown.
A reading can name the string property that holds its unit, as in
flow: Type.Number({ default: 0, unitProperty: "unit" }). While flow is bound, unit shows the
parameter’s units unless the placement sets unit. Values are never converted.
Ports and size
Section titled “Ports and size”Port coordinates are normalized between 0 and 1. A line stores the port ID, and the renderer places
it according to the instance’s size, mirroring, and rotation. Symbols keep their authored aspect
ratio unless stretch is true. On a stretchable symbol, a port can set anchorX or anchorY to
start, end, or center to keep its authored distance from that edge or the middle; the
default, scale, keeps its fraction. With grid metadata, each anchored distance must be a
multiple of 10.
Component hooks
Section titled “Component hooks”Inside a symbol component, useGraphicsSymbolViewport() returns the instance’s width, height,
rotation, mirrorX, mirrorY, the sides that have ports (portSides), the editing state,
scale (how much a proportional symbol is enlarged; 1 for a stretchable one), and bindings, the
live state of each bound property. Dimensions are in drawing units.
useGraphicsSymbolProperty(name) returns one property’s quality (fresh, stale, or
unknown), the binding’s digits, the parameter’s units for a value binding, and assigned:
whether the placement binds or sets the property. Unbound properties are fresh; a stale property
keeps its value; an unknown property keeps its static or default value, and the component decides
how to show it. While editing, a bound numeric property is unknown with its units.
formatGraphicsSymbolReading(value, state) formats a reading with that precision, and ”—” when it
is unknown. The host pauses CSS animations while editing; motion that the component manages itself
must check editing.
function Motor({ running }: Static<typeof properties>) { const { editing } = useGraphicsSymbolViewport(); const { quality } = useGraphicsSymbolProperty("running"); const color = quality === "unknown" ? "#cbd5e1" : running ? "#22c55e" : "#64748b"; const spinning = running && quality === "fresh" && !editing; // ...}The host rotates and mirrors the whole component. In SVG artwork, GraphicsSymbolText replaces
<text> so readings stay upright. GraphicsSymbolCaption, given the artwork’s SVG width and
height, draws a label along the bottom edge that moves beside the symbol when it is turned.
GraphicsSymbolCaptionBlock draws the tag and status lines below the artwork, unchanged by
mirroring. GraphicsSymbolUpright keeps a display face or a stack of readings upright around a
point.
Definition names, action labels, and property schemas are factories, such as
name: () => t("key"), so their text follows the active language.
Catalog metadata
Section titled “Catalog metadata”builtinGraphicsSymbols from @overvis/hmi-workspace-ui holds the built-in definitions of the
installed package version. defineGraphicsSymbol accepts an optional catalog: () => metadata
factory with category, industries, description, keywords, and examples, and optionally
family, variants, essential, units, and grid:
industriesuses fixed IDs:water,wastewater,pumping,energy,power,heating,hvac,temperature,manufacturing,warehouses,waste-recycling,quarries,compressed-air,agriculture,food-beverage,fuel-gas, andcontrols.familygroups related symbols, such asvalve.variantsare named physical variants, each with a stableid, a translatedname, and the property values that select it.graphicsSymbolVariants(properties, "body")derives them from a choice property.essentialnames the properties to bind for the symbol to show its operating state.unitsgives fixed display units of numeric properties, such as{ opening: "%" }.keywordsare extra search terms, such as synonyms and abbreviations.exampleshave a stableid, a translatedname, and property values, validated against the property schema when the definition loads.grid: { base: 10 }declares artwork designed for the 10-unit grid. The editor then computes valid sizes and keeps ports on the grid. OptionalminScaleandmaxScale, orminWidth,minHeight,maxWidth, andmaxHeight, narrow the sizes.
Each port may declare a role (process, air, electrical, signal, or material) and a
direction (in, out, or both). serializeGraphicsSymbolCatalog(definitions, locale) returns
the same details as graphics.symbols.get for any definitions, including workspace symbols.
@overvis/hmi-shared/graphics exposes the grid rules: graphicsSymbolSizes,
snapGraphicsSymbolSize, graphicsSymbolPortPoints, graphicsSymbolPortLayout, and
graphicsSymbolGeometryIssues, whose findings carry the expected value that aligning applies.
Named controls and commands
Section titled “Named controls and commands”A definition declares its control names, for example
actions: () => ({ activate: "Pump command" }). Inside its component,
useGraphicsSymbolAction("activate") returns label, disabled, pending, and activate for an
ordinary UI button. A symbol can have several named controls, and clicking one does not also run
the whole symbol’s action. A definition that declares a body, the equipment’s own area as
fractions of its box, takes whole-symbol clicks only on that body, so neighbors placed against it
keep their own.
const action = useGraphicsSymbolAction("activate");return ( <Button type="button" disabled={action.disabled} aria-busy={action.pending} onClick={action.activate} > {action.label ?? "Pump command"} </Button>);An instance’s actions.activate stores one action. A toggle looks like this:
{ "kind": "toggle", "source": { "kind": "slot", "slotId": "9edf66da-084f-4c85-81ba-260da6b418b2" }, "status": { "kind": "slot", "slotId": "62927ac1-a1a6-412a-9e35-c77aa3a1bb78" }, "onValue": "1", "offValue": "0", "onLabel": "Turn pump on", "offLabel": "Turn pump off", "confirm": true}Both slots must exist in the drawing. source is the writable command parameter; status is the
feedback parameter and may be a different one. A true or nonzero status offers the off action;
false or zero offers the on action. The control never takes a write acknowledgement as equipment
feedback. A fixed command instead uses kind: "command", source, value, label, and
confirm. Parameter details, history, and write actions and dashboard navigation can also be
assigned to a named control; write opens an input dialog for a value.
Confirmation is on by default: it shows the intended action with Confirm and Cancel. Without it, the command is sent on activation. A pending command cannot be sent again, failures stay visible, and missing or stale command or status values disable the control. If the configuration or the observed state changes while a confirmation is open, it asks for a new review. Read-only access and editing disable command controls, and the server still enforces write permissions.
The built-in hmi.button declares activate. With a toggle, it shows its label as a fixed name,
such as “Pump”, and a switch for its active property; the next action’s label is its tooltip and
the confirmation title. With other actions, it shows the action label, and a bound active fills
the button.
Images
Section titled “Images”PNG and JPEG images live in the workspace at graphics/images/<uuid>.png or
graphics/images/<uuid>.jpg; each UUID identifies one file. Image elements refer to the image
UUID, with ordinary position and size. Images stay single placements; they are not converted to
shapes. graphics.listImages returns the available images. Open dashboards reload an image when it
is replaced. Dashboard viewers can see the images. Removing a placement leaves the image for other
drawings, and a push that deletes an image still used by a dashboard is rejected. Camera
orientation is applied to JPEG images, and their metadata is removed.
POST /api/workspaces/<workspaceId>/graphics/images uploads one image as a multipart file, and
GET /api/workspaces/<workspaceId>/graphics/images/<assetId> reads one. Both accept the browser
sign-in or an API key in x-api-key; uploading needs editor access. Invalid input returns 400, an
upload over the limits 413, missing authentication 401, missing permission 403, and an unknown
image 404.