news 2026/9/23 17:37:16

cytoscape.js 动画队列延迟指南:使用 core.delay() 精准编排视图动画时序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
cytoscape.js 动画队列延迟指南:使用 core.delay() 精准编排视图动画时序
  • 数据可视化

【免费下载链接】cytoscape.js

Graph theory (network) library for visualisation and analysis

项目地址:https://gitcode.com/gh_mirrors/cy/cytoscape.js
点击查看免费下载

导读

delay()是 cytoscape.js 为动画系统提供的时间编排工具,允许你在动画链式调用的任意位置插入一段“静默等待期”,从而将视图变换(如fitpanzoom)与元素样式动画按时间顺序精确衔接。本文基于 documentation/md/core/delay.md 展开,结合仓库中src/define/animation.mjssrc/animation.mjs的底层实现,完整讲解 core 与 collection 两套delay()API 的用法、底层原理与实战场景。读完你将能够用几行链式代码实现“先聚焦 A 区域 → 停顿 → 再聚焦 B 区域”这类典型的多阶段视图编排。

一、delay() 是什么:不是定时器,而是队列中的“空动画”

cytoscape.js 的动画系统建立在动画队列(animation queue)之上:对同一个目标(core 实例或元素集合)连续调用animate()时,动画会按调用顺序排队执行。delay()的作用就是在这条队列里插入一个不产生任何视觉变化的占位动画,其运行时间恰好等于你指定的毫秒数。

核心delay()的源码实现在 src/define/animation.mjs:

delay: function(){ return function delayImpl( time, complete ){ let cy = this._private.cy || this; if( !cy.styleEnabled() ){ return this; } return this.animate( { delay: time, duration: time, complete: complete } ); }; }, // delay

从实现可以确认三个关键事实:

  1. delay()本质是对animate()的封装:它调用this.animate({ delay: time, duration: time, complete: complete }),所以它天然支持链式调用,并且返回的仍然是 core/collection 实例。
  2. delayduration都被设置为同一个值duration决定了该占位动画占据队列的时间长度,而delay用于让动画循环在到达该动画后的前time毫秒内不推进任何属性(详见下文原理小节)。
  3. complete回调被透传:延迟结束时若提供了complete回调,它会被装入该动画的 completes 数组并在动画完成时触发(见 src/animation.mjs 中_p.completes.push( _p.complete )的处理)。

在 src/core/animation/index.mjs 中,core 实例挂载了整套动画 API,其中就包括delaydelayAnimation

animate: define.animate(), animation: define.animation(), animated: define.animated(), clearQueue: define.clearQueue(), delay: define.delay(), delayAnimation: define.delayAnimation(), stop: define.stop(),

元素集合同样拥有delay()(见 src/collection/animation.mjs),因此“对节点做交错动画”这类场景也能直接使用。

注意:delay()的源码首先检查cy.styleEnabled(),在样式未启用(如纯 headless 数据场景)时会直接return this,即延迟不生效、链式调用继续。

二、核心示例:用 delay() 串联两次 fit 聚焦

原文档 documentation/md/core/delay.md 给出的示例是最经典的“多阶段视图聚焦”场景——先让视图适配到元素#j,等待 1 秒,再适配到元素#e

cy .animate({ fit: { eles: '#j' } }) .delay(1000) .animate({ fit: { eles: '#e' } }) ;

执行过程拆解如下:

阶段代码行为
1.animate({ fit: { eles: '#j' } })视图平移到并缩放到能完整显示#j的范围(默认持续 400ms,见下文时长说明)
2.delay(1000)队列在此暂停 1000ms,画面保持不动
3.animate({ fit: { eles: '#e' } })视图再次适配到#e

这段代码体现了delay()的两大实战价值:

  • 免去手写setTimeout与状态管理:无需手动记录动画是否结束、是否已到 1 秒,动画队列天然保证顺序。
  • fit等 core 视图操作无缝集成fit在 src/define/animation.mjs 中被解析为panzoom的动画目标,与delay同属一个动画队列,时序完全可控。

关于默认时长的补充

在上面的示例中,fit动画未指定duration。从 src/define/animation.mjs 可以看到默认值与速记值:

  • 未指定时默认duration = 400(毫秒);
  • 传入字符串'slow'解析为600
  • 传入字符串'fast'解析为200

所以示例实际的时间线约为:0–400ms 聚焦#j→ 400–1400ms 停顿 → 1400ms 起聚焦#e

三、delay() 的底层原理:动画循环中的 delay 判断

为什么delay()能让画面“停顿”而不产生跳动?答案在动画推进函数 src/core/animation/step.mjs 中:

if( ani_p.delay == null ){ // then update let startPos = ani_p.startPosition; let endPos = ani_p.position; // ... 位置、pan、zoom、样式属性的插值更新 }

也就是说:动画在推进时先检查自身的delay字段,只有delay == null才会执行属性插值更新;而delay()生成的动画带有非空的delay: time,因此在动画循环触达它的前time毫秒内,该动画虽然占用队列、推进进度,却不修改任何视觉属性——视觉上便形成了精确的停顿。

从 src/core/animation/index.mjs 可以看到,动画循环由startAnimationLoop()驱动,通过stepAll( now, cy )在每个帧推进所有活跃动画;headless(无渲染器)环境下同样依赖requestAnimationFrame循环。动画对象本身在 src/animation.mjs 中初始化,duration默认 1000ms,delaycomplete等参数均通过opts注入_private,这正是step读取ani_p.delay的数据来源。

四、进阶用法一:元素集合上的 delay() 实现交错动画

delay()不仅适用于 core 视图操作,也适用于元素集合。原文档姊妹篇 documentation/md/collection/delay.md 展示了元素颜色动画的两阶段切换:

cy.nodes() .animate({ style: { 'background-color': 'blue' } }, { duration: 1000 }) .delay( 1000 ) .animate({ style: { 'background-color': 'yellow' } }) ;

console.log('Animating nodes...');会在链式调用构建队列时立即执行,但视觉上的颜色变化严格遵循“变蓝 1 秒 → 停顿 1 秒 → 变黄”的顺序。

更进阶的用法是按索引递增延迟实现瀑布式交错动画,这在 documentation/md/collection/sort.md 的排序可视化示例中出现过:

var duration = 1000; nodes.removeStyle().forEach(function( node, i ){ node.delay( i * duration ).animate({ style: { 'border-width': 4, 'border-color': 'green' } }, { duration: duration }); });

这里对每个节点单独调用node.delay(i * duration),第i个节点会额外等待i * 1000ms,于是节点边框动画依次错峰开始,形成清晰的扫描效果。其原理是对每个元素独立维护动画队列delay()在 src/collection/animation.mjs 中同样委托给define.delay()this._private.cy || this保证了在元素上调用时能正确回溯到所属的 cy 实例。

五、进阶用法二:complete 回调与 delayAnimation()

delay()的第二个参数complete会在延迟结束时执行。例如需要在停顿后触发某个外部动作:

cy .animate({ fit: { eles: '#j' } }) .delay(1000, function(){ console.log('停顿结束,准备聚焦 #e'); }) .animate({ fit: { eles: '#e' } });

此外,仓库还提供了非自动播放的延迟动画——delayAnimation(time, complete),它与delay()的实现一一对应(见 src/define/animation.mjs):

delayAnimation: function(){ return function delayAnimationImpl( time, complete ){ let cy = this._private.cy || this; if( !cy.styleEnabled() ){ return this; } return this.animation( { delay: time, duration: time, complete: complete } ); }; }, // delay

区别在于:

API底层调用行为
delay(time, complete)this.animate({...})自动加入队列并立即开始播放
delayAnimation(time, complete)this.animation({...})只创建动画对象,不自动播放,需手动.play()

delayAnimation返回的动画对象具备 src/animation.mjs 中定义的全套控制方法——play()pause()stop()progress()promise()等。一个典型场景是配合样式过渡使用:在 src/style/apply.mjs 中,元素样式过渡(transition-delay)正是通过ele.delayAnimation( delay ).play().promise().then( resolve )来等待延迟结束再应用过渡样式:

if( delay > 0 ){ ele.delayAnimation( delay ).play().promise().then( resolve ); } else { resolve(); }

这说明delayAnimation在设计上就被引擎自身用于衔接“等待-执行”的异步流程,开发者完全可以在自己的代码中复用它来编写可暂停、可查询进度的延迟逻辑。

六、注意事项与最佳实践

  1. 只阻塞队列,不阻塞 JS 主线程delay()不是sleep(),动画循环期间 JavaScript 事件照常处理,console.log等代码会立即执行。
  2. 配合clearQueue()stop()使用:如果需要在用户交互时打断延迟,可调用cy.stop(true, false)cy.clearQueue()(实现见 src/define/animation.mjs),避免延迟动画继续占据队列。
  3. headless 环境行为一致:只要启用样式(styleEnabled()),动画循环在无渲染器环境同样运行(见 src/core/animation/index.mjs 的headlessStep()),但此时需要显式调用cy.destroy()停止循环。
  4. 时长单位time一律以毫秒为单位;0表示零延迟,等价于直接衔接下一动画。
  5. 集合与 core 的队列相互独立cy.delay()控制的是视图级动画(fit/pan/zoom)时序,eles.delay()控制的是元素级动画时序,两者互不阻塞。

总结

delay()是 cytoscape.js 动画链式编排中最轻量也最常用的时间控制手段:它通过“在队列中插入一段不更新属性的动画”实现了精确停顿,其实现位于 src/define/animation.mjs,延迟期间的静默行为由 src/core/animation/step.mjs 的ani_p.delay == null判断保证。无论是对 core 实例编排多阶段视图聚焦(fit+delay),还是对元素集合实现瀑布式交错动画(node.delay(i * duration)),亦或是借助delayAnimation().promise()编写可中断的异步时序,掌握这一个 API 就能显著提升图谱交互的质感与可控性。

  • 数据可视化

【免费下载链接】cytoscape.js

Graph theory (network) library for visualisation and analysis

项目地址:https://gitcode.com/gh_mirrors/cy/cytoscape.js
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 17:36:21

SECS/GEM协议源码解析:secs4j-master消息编码与GEM状态机实现

简介:secs4j-master 是一套面向半导体设备自动化领域的 Java 版 SECS/GEM 协议实现库,适合从事设备通信、工厂自动化系统开发的工程师与学习者使用。它把 SECS-I、SECS-II 的物理层与应用层协议,以及 GEM 规范中的设备初始化、状态报告、命令…

作者头像 李华
网站建设 2026/9/23 17:34:27

工业AI事故预警系统:小模型+规则引擎实现产线主动预防

1. 这不是又一个“AI喊口号”项目,而是工厂老师傅和算法工程师蹲在产线边改出来的真东西“基于AI的生产事故智能分析系统:从被动救火到主动预防”——这标题里没一个生僻词,但每个字都压着沉甸甸的现实重量。我干工业智能化落地十年&#xff…

作者头像 李华
网站建设 2026/9/23 17:32:37

ABAQUS模拟钢制重力锚在钙质土中的承载力分析

1. 项目概述在深海工程领域,重力锚作为固定海底管道、电缆和浮式结构的关键部件,其承载性能直接关系到整个工程系统的安全性和可靠性。钙质土作为一种特殊的海洋沉积物,广泛分布于热带和亚热带海域,其力学特性与常规陆相土体存在显…

作者头像 李华
网站建设 2026/9/23 17:30:48

OpenCV人脸识别考勤系统实战:从环境搭建到落地避坑

简介:这份资源是面向高校学生与Python初学者的人脸识别考勤系统完整项目源码,适合用作课程设计、期末大作业或OpenCV与dlib入门实战参考。项目围绕考勤管理场景,实现了用户注册登录、人脸检测与识别、打卡记录及数据查询等核心功能&#xff0…

作者头像 李华
网站建设 2026/9/23 17:28:59

双目立体视觉毕设指南:标定、匹配与深度图生成

简介:这份资源是面向计算机、人工智能、自动化、电子信息等专业学生与科研人员的双目摄像头立体视觉系统完整项目包,围绕相机标定、立体匹配与深度图生成三大核心环节展开,可作为毕业设计、课程设计或项目立项演示的参考方案。压缩包共190个文…

作者头像 李华