· 交互与动画
交互层:控制面板
ICEControlPanelManager 负责管理选中与变换工具(纯逻辑组件,无外观):
- 两类面板默认 disable;用户
mousedown命中可变换组件时,mouseDownHandler根据组件类型启用对应面板:component.isLine(线条类)→ 启用LineControlPanel;- 其它 → 启用
TransformControlPanel。
- 面板本身与手柄是
toolNodes,复用同一套组件模型(ICEControlPanel extends ICEGroup,手柄继承ICECircle)。 interactive/transformable等开关决定组件是否可交互、可变换。
拖拽与变换
- 拖拽:
mouseDown命中后注册mousemove/mouseup,mouseMoveEvtHandler调moveGlobalPosition(见 03 嵌套坐标 里全局位移需抵消父层变换)。 - 旋转手柄
RotateControl:AFTER_MOVE时用父组件absoluteOrigin计算旋转角,回写父组件rotate。 - 键盘:
keyboardEvtHandler支持方向键步进移动(ArrowUp/Down/Left/Right)、Delete删除组件。
连接线(Visio 风格)
ICELinkSlotManager 负责连线逻辑:
- 5 个共享插槽(
ICELinkSlot,位置 T/R/B/L/C = 上/右/下/左/中心)在ICE.init时创建、所有可连接组件复用,不随组件增删。 - 连线交互:拖动连线端点(
ICELinkHook)→HOOK_MOUSEMOVE阶段用包围盒相交检测(getMaxBoundingBox().isIntersect())找碰撞的linkable组件与插槽 →HOOK_MOUSEUP建立或断开links关系。 - 连线关系记录在
ICEPolyLine.state.links({ [端点位置]: { id, position } })。
动画
AnimationManager 订阅 ICE_FRAME_EVENT,对 animationMap 里的组件做补间:
动画配置挂在 props.animations,键可以是属性名或点路径('transform.rotate' / 'style.globalAlpha'),
取值有两种形态:
| 形态 | 写法 | 说明 |
|---|---|---|
| 单段 | { from, to, duration, easing? } | 在两个值之间补间 |
| 关键帧 | { keyframes: [{ offset, value, easing? }], duration } | offset 为 0~1 时间占比,缺省按顺序均分、超出会被夹紧、乱序自动排序;easing 写在段起始帧上,只作用于「该帧 → 下一帧」这一段(未写则回落到动画级 easing);时间轴之外的取值保持首/末帧值,不外推 |
- 取值可为数值或等长的数字数组(
transform.scale/transform.translate/transform.skew等按分量逐元素补间)。两端长度不一致或含非数字会被拒绝,并只console.warn一次 (不再像早期实现那样写出NaN破坏矩阵)。 - 通用配置:
duration、delay(延迟期内保持起始值,可做多属性错峰/多组件序列)、easing、loop、iterationCount、round。duration/easing可用主题motiontoken 的语义名 ('normal'/'out'/'spring'…)。 - 缓动分两层:
EasingProgress(归一化进度函数,t: [0,1] → 进度,纯函数、不读时钟)是唯一实现;Easing((from, to, duration, startTime)值语义,内部读Date.now())是它的适配层,保持历史签名。 弹簧类(spring/springSoft/springSnappy