
Если вы хоть раз разрабатывали SCADA-интерфейс, то знаете эту боль: унылые стандартные элементы, примитивная графика, дизайн уровня 90-х и никаких особо альтернатив, кроме как использовать свои изображения .png, а в качестве "анимации" использовать скрытие и отображение кучи картинок друг над другом.
Мы решили разработать свою библиотеку элементов для ОВиК. Взяли и "взломали" систему: наняли дизайнеров, отрисовали всё в Figme в SVG, а потом научили эти картинки анимироваться и управляться как родные блоки.
Что не так со стандартными элементами
Стандартные блоки в MasterSCADA4D вполне информативны, но не особо функциональны. Их набор довольно скуден и не гибок. Нет возможности легко адаптировать интерфейс к темной и светлой темам, скрыть ненужные элементы в объекте.

Мы сделали довольно много объектов и довольно часто слышали просьбы служб эксплуатации изменить стандартное, добавить темную тему, возможность кастомизации, в том числе цветовой.

Любое нестандартное оборудование, или элементы установки приходилось делать изображениями. Создавали несколько картинок с разным фоном \ цветом индикаторов: в режиме работа, останова, аварии. Затем скрывали ненужные через переменные, описывая в программе на ST логику отображения нужного режима. И так каждый раз. Проблема еще заключалась в том, что в таком решении кастомные объекты были непохожи на стандартные: другой стиль, нет анимации, нет возможности смены цвета (либо снова делать все через множество картинок с поочередным отображением, что при "анимации" давало "рваный" эффект)
"Взлом" стандартных элементов SCADA
Когда решили создать свою библиотеку устройств, в справке на SCADA довольно поверхностно было описано как это работает, как именно привязать управление или анимацию к элементу, какие поддерживаются эффекты и примеры их реализации.
Через техническую поддержку мы запросили исходники пары стандартных устройств и принялись ковырять их код.
Суть следующая: каждый элемент имеет изображение в формате .svg, в котором все его отрисованные элементы сгруппированы по функциональному назначению (например, по режимам работы) и написан код работы с ними, и файл .xml, в котором описываются все внешние параметры, которые будут управлять элементами в объекте.

Пример кода в файле .svg (достаточно открыть файл текстовым редактором)
<defs id="defs1" /> <style type="text/css" id="style1"><![CDATA[ #pump.Alarm #power_off{display:none} #pump.Alarm #power_on{display:none} #pump.Alarm #mode_visible{display:none} #pump.Alarm #alarm_pmp_on{display:inline} #pump.AlarmSensor #temp_visible{display:none} #pump.AlarmSensor #alarm_temp_on{display:inline} #pump.Start #power_off{display:none} #pump.Start #power_on{display:inline} #pump.no #temp_visible{display:none} #pump.noFC #power_visible{display:none} #pump.noFC #power_invisible{display:inline} #pump.noFC #mode_visible{display:none} ]]></style>
А в файле .xml с таким же названием, что и изображение в .svg указываем используемые параметры
<?xml version="1.0" encoding="utf-8"?> <SvgDef xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CreateCommonAvary="false"> <ParameterDefs> <ParameterDef Name="Rotation" DisplayName="Вращение" Type="STRING" ParamType="Attribute" ItemId="pump" Path="class"> <Value DisplayName="Выкл">Stop</Value> <Value DisplayName="Вкл">Start</Value> </ParameterDef> <ParameterDef Name="Alarm" DisplayName="Авария" Type="STRING" ParamType="Attribute" ItemId="pump" Path="class"> <Value DisplayName="Выкл">noAlarm</Value> <Value DisplayName="Вкл">Alarm</Value> </ParameterDef> <ParameterDef Name="AlarmSensor" DisplayName="Авария датчика" Type="STRING" ParamType="Attribute" ItemId="pump" Path="class"> <Value DisplayName="Выкл">noAlarmSensor</Value> <Value DisplayName="Вкл">AlarmSensor</Value> </ParameterDef> <ParameterDef Name="Invis" DisplayName="Наличие датчика" Type="STRING" ParamType="Attribute" ItemId="pump" Path="class"> <Value DisplayName="Нет">no</Value> <Value DisplayName="Да">yes</Value> </ParameterDef> <ParameterDef Name="InvisFC" DisplayName="Наличие ПЧ" Type="STRING" ParamType="Attribute" ItemId="pump" Path="class"> <Value DisplayName="Нет">noFC</Value> <Value DisplayName="Да">yesFC</Value> </ParameterDef> <ParameterDef DisplayName="Название" Type="STRING" ParamType="Attribute" ItemId="name_text" Path="content" /> <ParameterDef DisplayName="Статус" Type="STRING" ParamType="Attribute" ItemId="mode_text" Path="content" /> <ParameterDef DisplayName="Мощность" Type="STRING" ParamType="Attribute" ItemId="power_text" Path="content" /> <ParameterDef DisplayName="Размерность мощности" Type="STRING" ParamType="Attribute" ItemId="power_postfix_text" Path="content" /> <ParameterDef DisplayName="Значение датчика" Type="STRING" ParamType="Attribute" ItemId="temp_text" Path="content" /> <ParameterDef DisplayName="Размерность датчика" Type="STRING" ParamType="Attribute" ItemId="temp_postfix_text" Path="content" /> <ParameterDef Name="StateWorkColorOn" DisplayName="Цвет состояния Вкл" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="circle2_on" Path="stroke" /> <ParameterDef Name="StateWorkColorOff" DisplayName="Цвет состояния Выкл" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="circle2_off" Path="stroke" /> </ParameterDefs> </SvgDef>
Как на самом деле работает «взлом»: разбор на живом примере насоса
Возьмем за основу реальный файл насоса, который мы сделали для своей библиотеки. В нем есть:
индикация работы/останова с анимированным вращением;
авария (моргающая красная рамка);
отображение мощности в процентах (или текст «ВЫКЛ»);
опциональный датчик температуры;
два режима отображения: с частотным преобразователем (ПЧ) и без него.
Структура SVG: группировка по состояниям
Внутри файла pump.svg все элементы сгруппированы в теги <g> с понятными id:
power_on– вращающаяся синяя дуга (двигатель работает)power_off– статичная залитая дуга (двигатель остановлен)alarm_pmp_on– мигающая красная рамка и текст «АВАРИЯ»power_visible/power_invisible– показывают либо число (100 %), либо слово «ВЫКЛ»temp_visible/alarm_temp_on– нормальный или аварийный режим датчикаmode_visible– текстовый статус (например, «ВЫКЛ»)
Важное правило: в SVG нельзя просто взять и спрятать группу через
display:none– это не сработает. Мы используем каскадные CSS-правила, которые написаны внутри тега<style>в начале файла.
Вот пример из кода:
#pump.Alarm #power_off{display:none} #pump.Alarm #power_on{display:none} #pump.Alarm #mode_visible{display:none} #pump.Alarm #alarm_pmp_on{display:inline}
Если у корневого элемента с id="pump" есть класс Alarm, то:
спрятать группу
power_offспрятать группу
power_onспрятать
mode_visibleпоказать
alarm_pmp_on
Таким образом, переключая класс у корневого тега <g>, мы изменяем отображение целых блоков графики, чистая магия CSS + SVG.
Как SCADA управляет этими классами
В комплекте с SVG идет XML-файл с расширением .xml. В нём описано, какие параметры из проекта MasterSCADA4D за что отвечают.
Например:
Name="Alarm"– имя переменной внутри SCADA, которую вы привяжете к тегу (биту аварии).ItemId="pump"– какой элемент SVG мы меняем (наш корневой<g id="pump">).Path="class"– мы будем изменять атрибут class этого элемента.Значения: если переменная
Alarm= "Выкл", класс становитсяnoAlarm; если "Вкл" – класс становитсяAlarm. А в SVG уже есть правила, что делать при появлении классаAlarm(см. CSS выше).
Аналогично сделано для:
Rotation– переключает классыStop/Start(вращение анимации)InvisFC– переключает классыnoFC/yesFC(скрывает или показывает текст «100%»)AlarmSensor– отвечает за аварию датчика температуры
Анимация без скриптов
Вращение двигателя сделано через SVG-анимацию:
<animateTransform attributeName="transform" type="rotate" from="0 107.44529 130.13976" to="360 107.44529 130.13976" dur="2s" repeatDur="indefinite" />
Этот код вращает синюю дугу вокруг центра насоса. Анимация встроена прямо в группу power_on. Пока группа скрыта (класс Stop) – вращения нет. Как только SCADA присваивает класс Start – дуга появляется и начинает крутиться.
Аварийное мигание сделано через animate для прозрачности:
<animate attributeName="opacity" dur="1s" values="0.2;0.8;0.2" repeatCount="indefinite" />
Динамический текст и единицы измерения
В параметрах XML вы можете привязать любой текст внутри SVG:
<ParameterDef DisplayName="Мощность" Type="STRING" ParamType="Attribute" ItemId="power_text" Path="content" />
ItemId="power_text" – это идентификатор текстового элемента внутри SVG.Path="content" – значит, SCADA будет заменять содержимое этого текстового узла (то, что между <text>...</text>).
Точно так же можно менять цвет обводки или заливки:
<ParameterDef Name="StateWorkColorOn" DisplayName="Цвет состояния Вкл" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="circle2_on" Path="stroke" />
Это позволяет пользователю прямо в редакторе SCADA выбрать цвет работающего двигателя – без правки SVG.
Стоит учесть
Имена классов в CSS должны совпадать со значениями в XML (
<Value DisplayName="...">Точно_такое_же_имя_класса</Value>).Корневой элемент SVG (обычно
<g id="myDevice">) должен иметь атрибутclass, который SCADA будет менять.Если вы хотите динамически менять цвет – используйте атрибуты
strokeилиfill, а не CSS-классы.Анимации (
animate,animateTransform) работают только когда группа видима. Это экономит ресурсы.
После сохранения в среде разработки MasterSCADA4D добавляем объект, создаем окно, нажимаем на окно в дереве проекта правой кнопкой и Импорт SVG, после чего появится окно предпросмотра с привязкой параметров.

После подтверждения можно использовать наш собственный элемент в проекте со всеми его прописанными свойствами и анимациями.

Как это собрать воедино
Рисуете в Figma или Inkscape все состояния элемента, группируете их с понятными
id.Открываете SVG в текстовом редакторе, добавляете блок
<style>с CSS-правилами включения/выключения групп по классам.Создаёте XML с описанием параметров: для каждого переключателя (авария, работа, наличие датчика) указываете, какой
idи какой атрибут (class,content,stroke) менять.В MasterSCADA4D через меню «Импорт SVG» выбираете оба файла. Среда сама подхватит параметры из XML и предложит их привязать к тегам проекта.
Ссылка на исходники собственного элемента в данном примере будет в конце статьи
Разработка собственной библиотеки элементов в MasterSCADA4D
Инженеры творят могущество, но именно художники спасают мир от топорности.
Собрались, покопались в примерах, поняли как нужно и начали искать дизайнеров. Дизайнеры знают как будет красиво, но не понимают как это оборудование работает и какую индикацию нужно отображать, поэтому совместными усилиями начали прорабатывать варианты в Figma.

Составили Техническое задание, показали на живом оборудовании как это выглядит, обсудили как это должно выглядеть в SVG и приступили к работе. Вариантов было много...

Для каждого элемента было сделано несколько разных вариантов.
Огромная благодарность за терпимость и понимание чутких творцов

После чего начали компоновать в установки в различных комбинациях, чтоб выяснить оптимальное расположение индикаторов и выступающих частей. (например, чтоб слева от водяного нагревателя с трубами и насосом поместился электронагреватель, не перекрывая элементы друг друга).

Больше фото








После довольно долгой и кропотливой работы мы доделали свою библиотеку элементов для различных систем и потихоньку запускаем на новых объектах.

Очень много скринов















Всем красивых и информативных интерфейсов, а мы пошли дальше отрисовывать ОВиК.
Комментарии (14)

roman_grach
27.05.2026 17:38А как вывести число с заданными количеством знаков после запятой в текстовом атрибуте?

CYNTRON Автор
27.05.2026 17:38Мы сделали через программу в объекте. Там же добавили возможность выводить корректные значения при входных типа int и типа real.

roman_grach
27.05.2026 17:38Ещё есть штатная возможность при редактировании связи задать формат значения. Увидел после того, как попытался поэкспериментировать с вашим компонентом. Это конечно не так удобно, как при использовании стандартных компонентов, но ради эстетики можно потерпеть.

И да, забыл сказать: спасибо большое, что делитесь информацией!

ellusive3
27.05.2026 17:38Смысл примитивных интерфейсов в их информативности и легком считывании необходимых показателей. Все эти свистоперделки с тенями, крутыми анимациями и т.д. только усложняют работу с системой. Это не сайт, чтобы наряжать его, а мнемосхема объекта и в критический момент нужно определить проблему и среагировать

CYNTRON Автор
27.05.2026 17:38На вкус и цвет все фломастеры одинаковые.
Как в стандартных элементах отличить одну аварию от другой, если там всего один параметр аварии?
Или как в стандартных элементах отобразить переходный процесс, которого там не предусмотрено?
И я могу так долго продолжать.

EXEparadoxxx
27.05.2026 17:38Так и не понял, в чем заключался "взломали" и "заставили работать на svg", если это штатный функционал данной SCADA, которым многие разработчики вполне успешно пользуются. Да и примеры работы с динамическими svg как минимум пару лет присутствуют в документации.

CYNTRON Автор
27.05.2026 17:38Взломали - потому что из документации в то время было всего пару строк.
Штатный - да, но на тот момент нормально не описаный.
Пару лет - текст справки сравните с примером выложенным. Этот элемент у нас в ТГ канале как раз пару лет назад и был, а справка очень похожа на описание именно его. Совпадение.
NovoselovAG
Это за документированная возможность создания собственных элементов палитры. Даже видеоурок есть. От чего же такое название у публикации, про взлом?
CYNTRON Автор
На момент разработки ничего детального и подробного не было. Хорошо, если сделали. Но в тематических группах и сейчас довольно часто про это спрашивают.
CYNTRON Автор
Касательно документации - судя по ее тексту она и была (скорее всего) сделана на основе нашего поста в ТГ по круглому элементу из примера с год назад.
NovoselovAG
Ролик на ютубе появился 3 года назад а сама документация ранее. Пользовались ей при разработке проекта в 2022 году