动画功能详解 | HQ VISU Designer

工业页面中的动画用于强化状态识别、运动方向和异常提示。动画是否需要配置,应根据它能否帮助用户更快理解设备状态、位置变化或风险信息来判断。

Blink / Move / Rotate / Scale / Range动态表达避免滥用动画
动画

Before Use

工业页面中的动画用于强化状态识别、运动方向和异常提示。动画是否需要配置,应根据它能否帮助用户更快理解设备状态、位置变化或风险信息来判断。

动画 先记一个原则

动画是状态表达的放大器,不是状态表达本身。先把状态、颜色、文本和交互讲清楚,再决定哪些位置确实需要动态表达。

动画 动画的高价值场景

运动方向、液位变化、指针变化、设备旋转和报警提醒最适合使用动画。这类信息只靠静态图形时识别效率较低,动态表达可以帮助用户更快理解当前状态。

动画 动画降低可用性的场景

当动画过多、对象持续变化,或仅为了视觉效果而增加动画时,页面重点会被削弱,用户更难识别关键状态。

语法

动画字段支持哪些写法

动画字段分成数值表达式、布尔表达式、颜色值和模板变量。先分清字段类型,再填写表达式,后面的参数才容易稳定。

数值表达式

Move、Rotate、Scale 的输入值、位移、角度和缩放比例都可以写数值表达式。表达式必须能立即算出数字,不能直接放入异步请求。

  • 固定数值:120
  • Tag 数值:ReadTagDouble("<device-code>.<tag-code>", 0)
  • 对象尺寸:shape.width、shape.height
  • 计算表达式:shape.width * 2、shape.height * 0.5
ReadTagDouble("<device-code>.<tag-code>", 0)
shape.width
shape.height * 0.5
Definition 与最终字段的分工

Definition 是当前行为的准备区,适合读取 Tag、定义变量、计算中间值和准备函数。真正决定结果的是后面的 Condition、Value、Text、Fill、Stroke、Visibility、Offset、Angle 或 Scale 字段。Definition 中只声明变量但最终字段没有引用时,页面显示不会变化。

  • Definition:准备变量和函数
  • Condition / Enabled:返回布尔值
  • Text / Fill / Stroke:返回字符串
  • Input Value / Angle / Offset / Scale:返回数字
  • Visibility:返回布尔值
// Definition
var running = ReadTagBoolean("<device-code>.<run-tag>", false);
var color = running ? "#22C55E" : "#64748B";

// Fill
color
布尔表达式

Blink、Active、Enabled 和超限控制类字段通常需要布尔结果。建议写明确比较,不要只写一个含义不清的变量。

  • 二值 Tag:ReadTagBoolean("<device-code>.<tag-code>", false)
  • 状态码比较:state === 1
  • 组合条件:running === true && alarm === false
var running = ReadTagBoolean("<device-code>.<run-tag>", false);
var alarm = ReadTagBoolean("<device-code>.<alarm-tag>", false);
running === true && alarm === false
颜色值

颜色字段使用十六进制颜色值。普通颜色行为通常通过颜色选择器维护;Script Color 的 Fill 和 Stroke 可以返回颜色字符串。

  • 固定颜色:"#22C55E"
  • 脚本颜色:state === 1 ? "#22C55E" : "#EF4444"
  • 模板颜色:"<FILL_COLOR>"
var state = ReadTagInteger("<device-code>.<state-tag>", 0);
state === 1 ? "#22C55E" : "#EF4444"
字段结果类型清单

填写动画字段前,应先确认该字段需要的结果类型。Condition、Enabled、Active 和 Visibility 返回布尔值;Input Value、Offset、Angle、Scale、Limit、Clamp 返回数字;Fill、Stroke、Text 返回字符串;模板变量参与表达式时,应按字符串处理。字段类型明确后,后续排查会更直接。

  • 布尔值:Condition、Enabled、Active、Visibility
  • 数字:Input Value、Offset、Angle、Scale、Limit、Clamp
  • 字符串:Fill、Stroke、Text
  • 模板变量:在表达式中作为字符串使用
// Active
ReadTagBoolean("<PLC>.<RUN_TAG>", false)

// Offset Max
shape.width * 2

// Fill
ReadTagBoolean("<PLC>.<ALARM_TAG>", false) ? "#dc2626" : "#16a34a"
模板变量

模板变量格式为 <NAME>,变量名以字母或下划线开头。模板变量放入脚本表达式时,应写在字符串里。

  • Tag 字符串:"<PLC>.<RUN_TAG>"
  • 颜色字符串:"<FILL_COLOR>"
  • 模板变量参与 JavaScript 表达式时应放入字符串
ReadTagBoolean("<PLC>.<RUN_TAG>", false)
Global Script 适合放什么

多个页面都要使用的换算函数、格式化函数、颜色规则和项目级常量,可以放在 Global Script。当前页面独有的 Tag 名称、表格数据、弹窗范围和运行时状态仍应放在 Page Script,避免跨页面内容相互依赖。

  • 项目级换算:formatPressure(value)
  • 项目级颜色:getStateColor(state)
  • 项目级常量:const QUALITY_BAD_COLOR = "#EF4444"
  • 页面独有内容仍放 Page Script
Page Script 顶层变量和函数

当前页 Page Script 顶层声明的 var、let、const 和 function 可以被当前页动画字段引用。适合把量程、偏移量、Tag 名称和换算函数放在这里,再让 Move、Rotate、Scale、Script Color、Condition 等字段直接引用。

  • 顶层变量:const levelMax = 100
  • 顶层 Tag 名称:var levelTag = "<device-code>.<level-tag>"
  • 顶层函数:function readLevel() { ... }
  • 动画字段:readLevel() 或 levelMax
const levelMax = 100;
var levelTag = "<device-code>.<level-tag>";

function readLevel() {
  return ReadTagDouble(levelTag, 0);
}

// Scale / Input Value
readLevel()

// Scale / Input Max
levelMax
页面准备回调与初始动画

window.qteditPageReady 会在页面运行时准备完成后执行,适合做组件初始化、文本设置、显示控制和运行后刷新。用于初始动画计算的值,应优先放在 Page Script 或 Global Script 顶层。

  • 初始动画值优先引用顶层变量或函数
  • ready 回调适合调用 qtedit.setComponentText 等运行时方法
  • 回调内更新状态后需要驱动行为时,可写入运行时变量并刷新视图
var pumpVisible = true;

window.qteditPageReady = function() {
  qtedit.writeVariable("pumpVisible", pumpVisible);
  qtedit.refreshView();
};
位语法

读取整数 Tag 的单个位时,在完整 Tag 点名后使用 [0] 到 [31] 的位序号,通用写法是 `TAG[bit]`,例如 `Device.TAG[0]` 或 `<device-code>.<tag-code>[1]`。写入单个位时使用 Write Tag Bit,目标 Tag 填父整数 Tag,位号填写在 Bit Index 中。

  • 读取位语法:`TAG[bit]`
  • 读取位:ReadTagBoolean("<device-code>.<tag-code>[1]", false)
  • 写位目标:"<device-code>.<tag-code>"
  • Bit Index:0 到 31
  • Bit Action:Set、Reset、Toggle
ReadTagBoolean("<device-code>.<tag-code>[1]", false)
异步逻辑放置位置

表达式字段需要同步返回结果,不适合直接放 fetch、Promise 或定时器。需要异步读取外部数据时,应放在 Page Script 或 qteditPageReady 中处理,再把结果写入运行时变量或内部 JSON Tag,动画字段只读取已经准备好的结果。

  • 表达式字段:立即返回值
  • Page Script / qteditPageReady:处理异步准备
  • 动画字段:读取变量、Tag 或函数结果
  • 外部数据建议由 HQControl 接口或脚本层整理后再进入页面
Active、Enabled 和 Quality Border

`Active` 或 `Enabled` 用于决定行为当前是否参与计算;Quality Border 用于表达数据质量 GOOD / BAD。二者职责不同:Active 控制行为是否启用,Quality Border 告诉用户当前数据是否可信。需要在质量异常时隐藏对象,可结合 `Hide when quality BAD` 使用。

  • Active / Enabled:控制行为是否启用
  • Quality Border:表达数据质量
  • Hide when quality BAD:质量异常时隐藏对象
  • 业务状态仍应由实际 Tag 或状态规则表达
var enabled = ReadTagBoolean("<PLC>.<ENABLE_TAG>", false);
var qualityGood = ReadTagQualityGood("<PLC>.<VALUE_TAG>");

// Active
enabled && qualityGood
Move

Move:用数值映射对象位移

Move 把一个输入值换算成一个方向上的位移。它适合对象整体移动,不适合对象自身变长或缩短。

功能是什么

Move 读取一个数值,把这个数值按输入范围换算成百分比,再把百分比映射到 Offset Min 和 Offset Max 之间,最终让对象沿水平或垂直方向移动。

  • 0% 对应 Offset Min
  • 100% 对应 Offset Max
  • 中间值按比例移动
关键字段

Input Value 是来源值;Input Min / Input Max 是来源值范围;Clamp Min / Clamp Max 是参与换算的范围;Offset Min / Offset Max 是实际位移距离;Direction 决定水平或垂直。

  • Input Value:数值表达式
  • Input Min / Input Max:来源范围
  • Clamp Min / Clamp Max:换算范围
  • Offset Min / Offset Max:实际移动距离
  • Direction:Horizontal 或 Vertical
Input 和 Clamp 的区别

Input Min / Input Max 描述正常来源范围;Clamp Min / Clamp Max 描述参与换算的限制范围。通常二者相同。需要允许来源值超出正常范围但限制画面移动距离时,再单独调整 Clamp。

  • 正常场景:Input Min / Max 与 Clamp Min / Max 保持一致
  • 来源值可超限但画面不继续移动:Clamp 限制位移
  • 需要超限隐藏时,开启 Hide if value exceeds limits
支持写法

Offset 不是百分比,而是画布距离。可以写固定数字,也可以使用当前对象尺寸。

  • 向右移动一个对象宽度:shape.width
  • 向左移动一个对象宽度:-shape.width
  • 向下移动半个对象高度:shape.height * 0.5
  • 向上移动两个对象高度:-shape.height * 2
Input Value = ReadTagDouble("<device-code>.<position-tag>", 0)
Input Min = 0
Input Max = 100
Offset Min = 0
Offset Max = shape.width
Direction = Horizontal
配置顺序

先确定来源 Tag 和量程,再确定移动方向,最后填写 Offset。配置完成后,再决定是否开启超限隐藏和质量边框。

  • 第一步:确认输入值和量程
  • 第二步:选择 Horizontal 或 Vertical
  • 第三步:填写 Offset Min / Offset Max
  • 第四步:按需要开启 Hide if value exceeds limits
  • 第五步:按需要开启 Quality Border
适用和边界

滑块、行程、位置指示适合 Move。液位柱、进度条和填充条通常不应使用 Move,因为它们表达的是长度变化,应使用 Scale。

Rotate

Rotate:用角度表达方向和旋转

Rotate 根据角度值旋转对象。真正关键的是 Pivot,也就是对象围绕哪个位置旋转。

功能是什么

Rotate 读取当前角度,把对象围绕指定 Pivot 旋转。它适合风机、指针、阀门和方向件。

  • Current Angle 决定当前角度
  • Max Rotation 限制最大角度
  • Pivot 决定旋转中心
关键字段

Current Angle 填角度表达式;Max Rotation 填最大旋转角度;Pivot 选择旋转中心。需要偏移中心时使用相关 X / Y 字段。

  • Current Angle:角度值或角度表达式
  • Max Rotation:90、180、360 等最大角度
  • Pivot:Centre、Top、Bottom、Left、Right
角度值和运行状态要分开

Rotate 负责角度或旋转表达,不负责判断设备是否处于运行状态。风机、指针和阀门常见做法是:Rotate 表达方向或角度,State Color 表达运行、停止、报警或手自动状态。

  • 角度来源:Current Angle
  • 运行状态:State Color 或 Multi-State Color
  • 数据质量:Quality Border
支持写法

角度字段可以直接读取 Tag,也可以根据百分比换算成角度。

  • 直接角度:ReadTagDouble("<device-code>.<angle-tag>", 0)
  • 百分比换算:ReadTagDouble("<device-code>.<speed-tag>", 0) * 3.6
  • 读取原始角度:shape.rotation
Current Angle = ReadTagDouble("<device-code>.<angle-tag>", 0)
Max Rotation = 360
Pivot = Centre
配置顺序

先确认对象的机械中心,再选择 Pivot。对象中心选错时,即使角度正确,旋转也会显得不稳定。

  • 第一步:确认对象原始方向
  • 第二步:选择 Pivot
  • 第三步:填写 Current Angle
  • 第四步:填写 Max Rotation
  • 第五步:按需要开启质量边框
适用和边界

风机、指针和阀门适合 Rotate。对象只是左右移动时应使用 Move;对象长度变化时应使用 Scale。

Scale

Scale:用比例表达增长和缩短

Scale 根据输入值改变对象尺寸。它的关键不是放大多少,而是哪一边固定。

功能是什么

Scale 把输入值换算成一个比例,让对象从指定边缘向外增长或缩短。它适合液位、进度条、负载条和填充条。

  • Scale Min 对应最低比例
  • Scale Max 对应最高比例
  • Anchor Edge 决定固定边
关键字段

Input Value 是来源值;Input Min / Input Max 是来源范围;Clamp Min / Clamp Max 是参与换算的范围;Scale Min / Scale Max 是缩放比例;Anchor Edge 决定固定边。

  • Scale Min / Scale Max:常见为 0 到 1 或 0.5 到 1.5
  • Anchor Edge = Bottom:底部固定,向上增长
  • Anchor Edge = Left:左侧固定,向右增长
  • Anchor Edge = Right:右侧固定,向左增长
对象绘制方式会影响效果

Scale 适合对一个独立填充对象做比例变化。液位、进度条和负载条通常应拆成背景容器和前景填充对象,再让前景对象按固定边增长。不要直接缩放包含文字、边框和图标的复杂组合,否则文字和边框也会跟随变形。

  • 背景容器保持固定
  • 前景填充对象参与 Scale
  • 文字和单位建议单独放置
  • 复杂设备组不直接整体 Scale
支持写法

Scale 的输入值使用数值表达式,比例字段使用数值或计算表达式。

  • 液位:Scale Min = 0,Scale Max = 1
  • 轻微变化:Scale Min = 0.8,Scale Max = 1.2
  • 输入值:ReadTagDouble("<device-code>.<level-tag>", 0)
Input Value = ReadTagDouble("<device-code>.<level-tag>", 0)
Input Min = 0
Input Max = 100
Scale Min = 0
Scale Max = 1
Anchor Edge = Bottom
配置顺序

先确定对象应从哪一边增长,再设置 Anchor Edge。液位类对象通常固定底部,进度条通常固定左侧。

  • 第一步:确认增长方向
  • 第二步:设置 Anchor Edge
  • 第三步:填写输入量程
  • 第四步:填写 Scale Min / Scale Max
  • 第五步:按需要叠加 Range Color
适用和边界

Scale 适合长度或填充比例变化。对象整体移动时使用 Move;对象转动时使用 Rotate。

Range

Range:用区间表达连续值状态

Range Color 把一个数值拆成多个区间,用颜色、边框或显隐表达当前区间。

功能是什么

Range Color 读取一个数值,把它落入预设 Limits 的区间,再根据区间选择颜色、边框和显隐状态。

  • 适合连续值
  • 适合低、中、高、危险等区间
  • 默认 4 个分割点形成 5 个区间
关键字段

Rule 返回数值;Limits 是区间分割点;Fill Colors、Stroke Colors、Visible States 分别决定每个区间的填充、边框和显隐。

  • Rule:数值表达式
  • Limits:区间边界
  • Fill Colors:区间填充色
  • Stroke Colors:区间边框色
  • Visible States:区间显隐
Limits 区间划分

Limits 按从小到大排列。4 个分割点会形成 5 个区间:小于第一个分割点、第 1 到第 2 区间、第 2 到第 3 区间、第 3 到第 4 区间、大于等于最后一个分割点。颜色数量应与区间数量对应。

  • Limits 示例:20, 40, 60, 80
  • 形成区间:<20、20-40、40-60、60-80、>=80
  • 先确定单位和工程量程,再确定区间颜色
支持写法

Rule 通常读取模拟量 Tag。Limits 使用从低到高的数值。

var value = ReadTagDouble("<device-code>.<temperature-tag>", 0);
value

Limits = 20, 40, 60, 80
配置顺序

先确认数值单位和量程,再确定区间边界。边界写完后,再设置每个区间的颜色和显隐。

  • 第一步:确认 Tag 和单位
  • 第二步:填写 Rule
  • 第三步:填写 Limits
  • 第四步:设置每个区间颜色
  • 第五步:按需要开启质量边框
适用和边界

温度、压力、负载、液位等连续值适合 Range。固定状态码使用 Discrete Color;复杂优先级状态使用 Multi-State Color。

选型

先选对动画类型,再谈参数

动画配置首先要确认表达目标。类型选错后,即使参数正确,也可能无法准确表达设备状态。

Blink:用于关键提醒

Blink 最适合报警和强提醒。它不用于表达连续过程,而用于提示用户关注少数关键对象。

Move:位置在变,就用位移表达

当对象本质上是在页面里沿某个方向移动时,例如滑块、行程位置、水平推进件,应使用 Move 表达位置变化。

Rotate:方向或角度在变,就用旋转表达

Rotate 适合指针、风机、阀门和方向件。配置重点是旋转中心与对象机械特征一致。

Scale:长度在变,就用缩放表达

Scale 最适合液位、进度条、增长条、长度变化件。它真正关心的是哪一边固定、哪一边变化。

Range:值跨区间变化时,动态和颜色往往一起看

Range 本身可以是颜色区间,也可以和几何范围映射配合。它最适合让用户快速判断数值落在哪个段位,而不是只看一个单一数字。

Blink 动画
Blink 动画

Blink 只适合把注意力拉向少数关键对象。

Move 动画
Move 动画

位置真的在变时,优先用 Move,而不是绕着写脚本。

Rotate 动画
Rotate 动画

角度变化和方向感最适合用 Rotate 表达。

Scale 动画
Scale 动画

长度变化和增长效果通常更适合 Scale。

对比

Move 和 Scale 的选择边界

Move 表达对象位置变化,Scale 表达对象尺寸或填充比例变化。二者应按对象物理含义区分。

Move 优先的场景

如果对象整体坐标发生变化,例如滑块向右移动、行程块沿轨道移动、位置标记上移,应选择 Move。

Scale 优先的场景

如果对象一边固定,另一边增长或收缩,例如液位柱向上增长、进度条向右增长,应选择 Scale。

液位类对象的典型选择

液位类对象通常应由背景容器和前景填充对象组成。背景容器保持不变,前景填充对象使用 Scale,并将 Anchor Edge 设置为 Bottom。若使用 Move,画面表达会变成整体位置变化,不符合液位增长的物理含义。

Move 用法
Move 用法

整体平移类效果看 Move。

Scale 用法
Scale 用法

一边固定、一边增长类效果看 Scale。

规则

动画数量控制:越重要的状态,越应配置动画

动画不应平均分配给所有对象。清晰稳定的页面通常只在最需要动态表达的层级配置动画。

把动画留给最关键的信息

优先给报警、运动方向、旋转设备、液位变化和进度变化这类静态表达不够直观的信息加动画。普通状态色、普通文字和普通按钮通常不需要额外动画。

动画和颜色应分层表达

如果对象已经通过颜色清晰表达状态,通常不需要再配置同等强度的动画。颜色和动画应分层表达:颜色负责基础状态,动画只强化重点状态。

整页动画应控制数量

如果一整页大量对象同时闪烁、旋转或缩放,用户注意力会被分散,关键状态反而不突出。建议只在报警、方向、旋转设备和关键过程变化上配置动画。

Post Operations 只做补充

Post Operations 适合在几何结果计算完成后补充文本、边框、显隐或运行时变量,不应承载第二套主要 Move、Rotate、Scale 逻辑,也不应承担核心设备写值。主要几何关系应放在对应行为字段中维护。

  • 适合补充展示结果
  • 适合同步运行时变量
  • 不适合作为主要几何规则
  • 不适合作为关键写值入口
示例

几个最常见的动画表达场景

这一节不讲抽象概念,直接讲页面里最容易遇到的几种动态表达。

风机运行:旋转 + 运行状态色

风机通常最适合用 Rotate 表达运行,同时配置基础运行状态色。旋转表达设备正在转动,颜色表达设备是否处于运行态。

报警灯:闪烁 + 报警文本

报警灯最适合 Blink,旁边再配 Script Text 或 Tag Text 显示报警内容。这样用户既知道有问题,也知道具体是什么问题。

液位条:Scale + 区间颜色

液位通常最适合 Scale 从底边往上长,再叠一个 Range Color 或状态区间颜色。这样既有形态变化,也有区间感知。

滑块 / 行程:Move + 位置区间

滑块、行程件和推进块更适合 Move。必要时可以再根据位置区间改变颜色,但不要把本该位移的对象做成整体缩放。

Range 动态表达
Range 动态表达

区间感和动态感结合起来时,用户更容易快速读懂数值状态。