Если вы хоть раз разрабатывали 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.
Составили Техническое задание, показали на живом оборудовании как это выглядит, обсудили как это должно выглядеть и приступили к работе. Вариантов было много…
Для каждого элемента было сделано много разных вариантов.
Огромная благодарность за терпимость и понимание чутких творцов
После чего начали компоновать в установки в различных комбинациях, чтоб выяснить оптимальное расположение индикаторов и выступающих частей. (например, чтоб слева от водяного нагревателя с трубами и насосом поместился электронагреватель, не перекрывая элементы друг друга).
Больше фото
После довольно долгой и кропотливой работы мы доделали свою библиотеку элементов для различных систем и потихоньку запускаем на новых объектах.
Очень много скринов
Всем красивых и информативных интерфейсов, а мы пошли дальше отрисовывать ОВиК.
ссылка на оригинал статьи https://habr.com/ru/articles/1040060/