|
<< Click to Display Table of Contents >> Navigation: Создание окон для клиента визуализации > Рекомендации по созданию окон > Динамизация SVG элементов > Практические сценарии динамизации > Регулирование уровня воды в ёмкости |
Сценарий: Регулировать уровень воды, фон воды и фон емкости при помощи динамизации SVG.
Ссылка на ресурсы документации: https://disk.yandex.ru/d/Rz1qXThYFc3vDA
1.Первым этапом создадим простую емкость с водой. В качестве графического редактора воспользуемся Figma:
a.Размеры SVG 68x100. Убираем белый фон:

b.Создаем прямоугольник с размерами 68x100, закругленными углами 10 и заливкой фона #C2C2C2:

c.Продублируем прямоугольник. Дубликат будет использоваться в качестве маски для воды:

d.Теперь создадим небольшой квадрат 68x68, который будет выступать в роли воды. Заливка квадрата #2966FF:

e.Далее нужно создать маску. Для этого нужно выбрать дубликат серого прямоугольника и синий квадрат. В Figma необходимо выбрать Use as mask:

Маску (Mask) не следует путать с Булевыми операциями (Boolean operations). Маска используется, чтобы скрыть часть слоя, не повлияв на саму фигуру. Булевы операции нужны для создания сложных фигур. Делается это при помощи комбинирования фигур и булевых операций: объединения (union), вычитания (substract), пересечения (intersect) и исключения (exclude). Ниже приведены примеры булевых операций в разных графических редакторах:
- Figma:

- Adobe Illustrator:

- Inkscape:

f.Теперь при регулировании слоя маски, на скриншоте это "Rectangle 23", можно изменить уровень воды в емкости:


g.Выставим высоту слоя маски 10 и экспортируем SVG:


2.Откроем SVG:
<svg width="68" height="100" viewBox="0 0 68 100" fill="none" xmlns="http://www.w3.org/2000/svg"> <g clip-path="url(#clip0_13609_12389)"> <rect width="68" height="100" rx="10" fill="#C2C2C2"/> <mask id="mask0_13609_12389" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="68" height="100"> <rect width="68" height="100" rx="10" fill="#C2C2C2"/> </mask> <g mask="url(#mask0_13609_12389)"> <rect y="90" width="68" height="10" fill="#2966FF"/> </g> </g> <defs> <clipPath id="clip0_13609_12389"> <rect width="68" height="100" fill="white"/> </clipPath> </defs> </svg> |
3.Найдем строку "<rect y="90" width="68" height="10" fill="#2966FF"/>" и в ней изменим атрибут "height" с 10 на 5:
<rect y="90" width="68" height="5" fill="#2966FF"/>

4.Видно, что вода меняется от координатной точки (y="90") вниз. Данную проблему можно решить двумя способами:
Примечание: Почему вода смещается вниз, а не вверх?
- В SVG координатная система начинается в левом верхнем углу (черный квадрат на изображении);
- Координата "y" указывает на верхнюю границу элемента относительно SVG;
- В итоге: У тега <rect> значение y="90" означает, что верхняя граница фиксирована на 90, а свойство height определяет, насколько элемент будет распространяться вниз, т.е. y = 90 + height.
❖Способ 1. Вертикально отзеркалить SVG проектным способом: В теге SVG <rect y="90" width="68" height="5" fill="#2966FF"/> нужно изменить координату "y" на 0.
<rect y="0" width="68" height="5" fill="#2966FF"/>
Но после импорта и при размещении данной SVG на мнемосхему нужно будет постоянно отзеркаливать элемент, либо создавать отдельный отзеркаленный экземпляр емкости.
Благодаря этому вода будет меняться не сверху вниз, а снизу вверх.

❖Способ 2: Вертикально отзеркалить в SVG: Необходимо изменить в теге SVG <rect y="90" width="68" height="5" fill="#2966FF"/> координату "y" на 0. И также в тег <svg> добавить новый атрибут transform для отражения по вертикали всей SVG: transform="scale(1 -1)":
<svg width="68" height="100" viewBox="0 0 68 100" fill="none" xmlns="http://www.w3.org/2000/svg" transform="scale(1 -1)"> <g clip-path="url(#clip0_13609_12389)"> <rect width="68" height="100" rx="10" fill="#C2C2C2"/> <mask id="mask0_13609_12389" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="68" height="100"> <rect width="68" height="100" rx="10" fill="#C2C2C2"/> </mask> <g mask="url(#mask0_13609_12389)"> <rect y="0" width="68" height="10" fill="#2966FF"/> </g> </g> <defs> <clipPath id="clip0_13609_12389"> <rect width="68" height="100" fill="white"/> </clipPath> </defs> </svg> |
Примечание: Что означает scale(1 -1)?
•Первый параметр scale означает масштаб по оси X. Второй по оси Y;
•1 - по горизонтали (X) означает что ничего не изменится;
•-1 - по вертикали (Y) означает что весь SVG зеркально отразится.
В Visual Code превью SVG может ошибочно показывать, что вода осталась сверху, а не снизу, после добавления "transform="scale(1 -1)"":
Это баг плагина для предпросмотра SVG. Перепроверьте результат с помощью любого браузера: в нём все отображается корректно.
На изображении ниже в качестве перепроверки SVG использовался браузер Edge:

5.Добавляем в SVG два id:
a.Для регулирования уровня воды и фона воды: id="water";
b.Для регулирования фона емкости: id="tank_bg".
<svg width="68" height="100" viewBox="0 0 68 100" fill="none" xmlns="http://www.w3.org/2000/svg" transform="scale(1 -1)"> <g clip-path="url(#clip0_13609_12389)"> <rect id="tank_bg" width="68" height="100" rx="10" fill="#C2C2C2"/> <mask id="mask0_13609_12389" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="68" height="100"> <rect width="68" height="100" rx="10" fill="#C2C2C2"/> </mask> <g mask="url(#mask0_13609_12389)"> <rect id="water" y="0" width="68" height="10" fill="#2966FF"/> </g> </g> <defs> <clipPath id="clip0_13609_12389"> <rect width="68" height="100" fill="white"/> </clipPath> </defs> </svg> |
SVG готов.
6.Теперь сделаем импорт SVG:
Важно! Во время создания документации существует небольшой визуальный баг, который может ввести в замешательство.

Окно импорта можно отрегулировать, чтобы можно было увидеть поле ввода Атрибута элемента SVG:

Параметры в окне импорта:
Имя параметра |
Id элемента SVG |
Атрибут элемента SVG |
water_value |
water |
height |
water_color |
water |
fill |
tank_bg |
tank_bg |
fill |

Импорт выполнен успешно, нужные свойства появились:

7.Создаем окно для проверки. Разместим в него вертикальный ползунок и две кнопки выбора цвета и SVG:
a.Вертикальный ползунок и его свойство Текущее значение связываем со свойством water_value SVG как входящую связь:

b.Первую кнопку цвета и ее свойство Значение связываем со свойством water_color SVG как двунаправленную связь:

c.Вторую кнопку цвета и ее свойство Значение связываем со свойством tank_bg SVG как двунаправленную связь:

8.Назначаем Окно как стартовое и запускаем проект на исполнение.
При регулировании с помощью вертикального ползунка и кнопок выбора цвета можно динамически менять SVG:



9.В качестве бонуса сделаем дубликат water_tank SVG и XML с суффиксом "_with animation", чтобы добавить анимацию.
Для этого нужно зайти в SVG и в селектор #water добавить свойство "transition: height 1s;", которое будет отвечать за анимацию атрибута height.
<svg width="68" height="100" viewBox="0 0 68 100" fill="none" xmlns="http://www.w3.org/2000/svg" transform="scale(1 -1)"> <style type="text/css"><![CDATA[ #water{ transition: height 1s; } ]]> </style> <g clip-path="url(#clip0_13609_12389)"> <rect id="tank_bg" width="68" height="100" rx="10" fill="#C2C2C2"/> <mask id="mask0_13609_12389" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="68" height="100"> <rect width="68" height="100" rx="10" fill="#C2C2C2"/> </mask> <g mask="url(#mask0_13609_12389)"> <rect id="water" y="0" width="68" height="10" fill="#2966FF"/> </g> </g> <defs> <clipPath id="clip0_13609_12389"> <rect width="68" height="100" fill="white"/> </clipPath> </defs> </svg> |
Импортируем SVG с анимацией и выставляем ее в Окно мнемосхемы для сравнения.
10.Готово, анимация работает:

