- 数据可视化
【免费下载链接】cytoscape.js
Graph theory (network) library for visualisation and analysis
本文围绕 cytoscape.js 核心 API 中的cy.stop()方法展开,讲解如何中断视口级动画(如fit、pan、zoom等核心动画),并结合仓库源码剖析其clearQueue、jumpToEnd两个可选参数的真实作用,以及它与ele.stop()、ani.stop()的关系。读完本文,你将能在实际项目中精准地控制动画的暂停、中止与清理,避免动画队列堆积造成的性能问题。
一、为什么需要cy.stop()
cytoscape.js 中,cy.animate()用于对核心视口(viewport)发起平滑动画,例如平移(pan)、缩放(zoom)、适配元素(fit)等。这类动画默认会完整播放到结束为止,但在交互式应用中,用户往往会在动画中途触发新的操作(比如拖拽、滚轮缩放、切换视图)。此时如果旧动画继续播放,会与新操作互相"打架",导致视口位置错乱或卡顿。
cy.stop()就是为此设计的:它立即终止当前正在播放的核心动画,让视口停留在当前状态,并把控制权交还给开发者。
二、基本用法:完整示例
documentation/md/core/stop.md给出了最典型的应用场景——在动画播放中途将其停止:
cy.animate({ fit: { eles: '#j' } }, { duration: 2000 }); // stop in the middle setTimeout(function(){ cy.stop(); }, 1000);这段代码的含义是:
- 先让视口用 2000ms 平滑地缩放、平移以适配元素
#j(fit动画); - 在动画进行到一半(1000ms)时调用
cy.stop(); - 动画被立即中断,视口停留在 1000ms 时刻对应的中间位置。
这里的fit属于核心级动画,只有cy.stop()(而不是元素集合的stop())能够中止它。关于cy.animate()的更多可用属性(pan、zoom、fit及duration等),可参考 documentation/md/core/animate.md。
三、cy.stop()的两个可选参数:clearQueue与jumpToEnd
从 src/define/animation.mjs 的源码可以看到,stop的实现签名是:
stop: function(){ return function stopImpl( clearQueue, jumpToEnd ){ // ... }; }即cy.stop( clearQueue, jumpToEnd ),两个参数都是可选的布尔值,默认为false:
| 参数 | 类型 | 默认值 | 作用 |
|---|---|---|---|
clearQueue | boolean | false | 是否清空尚未执行的动画队列(queue)。为true时,排队等待播放的后续动画全部被丢弃;为false时,队列中的动画在停止后仍会继续依次播放。 |
jumpToEnd | boolean | false | 是否直接跳到动画终点。为true时,当前动画立即完成(跳到最终状态);为false时,动画停留在当前进度。 |
从源码看两个参数的真实行为
在 src/define/animation.mjs 中,实现逻辑非常直白:
for( let j = 0; j < anis.length; j++ ){ let ani = anis[ j ]; let ani_p = ani._private; if( jumpToEnd ){ // next iteration of the animation loop, the animation // will go straight to the end and be removed ani_p.duration = 0; } } // clear the queue of future animations if( clearQueue ){ _p.animation.queue = []; } if( !jumpToEnd ){ _p.animation.current = []; }关键点如下:
jumpToEnd: true的实现技巧:它并不直接改写进度,而是把当前动画的duration置为0。在动画循环中,duration === 0时进度会被直接判定为1(见 src/core/animation/step.mjs),于是下一次循环迭代时动画"直接走到终点"并自然完成,随后触发complete回调。这保证了跳转终点时动画的收尾逻辑(回调、样式最终态)仍然完整执行。clearQueue: true:直接清空目标对象私有状态_p.animation.queue中的全部排队动画,实现"停止并清空后续任务"的效果。- 立即停止(两者皆默认 false):将
_p.animation.current置为空数组,正在播放的动画即刻从当前帧中断,既不走完也不跳终。
无论采用哪种组合,方法末尾都会调用cy.notify('draw')触发一次重绘通知——源码注释特别说明:"the animation loop doesn't do it for us onstop",即停止动作本身不会经由动画循环触发渲染通知,因此需要显式通知渲染器刷新画面(见 src/define/animation.mjs)。
典型组合场景
// 立即停止当前动画,同时丢弃后续排队的动画 cy.stop( true ); // 立即跳到动画终点(常用于"快速完成过渡") cy.stop( false, true ); // 停止当前动画并清空队列,然后直接跳到终点 cy.stop( true, true );四、底层原理:cy.stop()在动画系统中的位置
要理解cy.stop(),需要先了解 cytoscape.js 的动画运行模型:
- 动画对象:
cy.animation()/cy.animate()会创建一个Animation实例(见 src/animation.mjs),内部记录duration、progress、playing、started等状态,以及目标对象的起始与终止位置、平移、缩放、样式。 - 挂载队列:
Animation.prototype.hook()将动画挂到目标对象的_private.animation.queue(排队)或current(当前播放)列表;元素动画还会通过cy.addToAnimationPool()把元素加入动画池(见 src/core/animation/index.mjs 与 src/animation.mjs)。 - 动画循环:核心的
stepAll()每帧遍历动画池中的元素与核心实例,先从queue取出下一个动画放入current,再逐帧调用step()计算插值并应用(见 src/core/animation/step-all.mjs 与 src/core/animation/step.mjs)。动画结束后从current移除并触发complete回调。
cy.stop()正是作用于上述模型中的第 2、3 步:它直接操作核心实例_private.animation的current与queue两个列表,绕开动画循环,立即改变状态。同时,stop方法被挂在核心对象的原型方法集中(stop: define.stop(),见 src/core/animation/index.mjs),因此cy、元素(ele)和元素集合共用同一份stopImpl实现——区别仅在于this指向的目标不同。
与ele.stop()、ani.stop()的区别
cytoscape.js 中有三个容易混淆的stop,它们服务不同粒度:
| 方法 | 目标 | 用途 | 参考 |
|---|---|---|---|
cy.stop() | 核心实例 | 停止视口动画(pan / zoom / fit / center 等) | documentation/md/core/stop.md |
ele.stop()/collection.stop() | 元素 / 元素集合 | 停止元素的位置、样式动画 | documentation/md/collection/stop.md |
ani.stop() | 单个 Animation 对象 | 停止指定的单个动画实例,便于清理和复用 | documentation/md/animation/stop.md |
在Animation.prototype.stop的实现中(见 src/animation.mjs),动画实例被标记为stopped = true并从播放状态摘除;随后动画循环在 src/core/animation/step-all.mjs 中检测到ani_p.stopped时将其从current列表移除并复位hooked、playing、started状态。
例如,元素动画的停止示例(来自 documentation/md/collection/stop.md):
cy.nodes().animate({ style: { 'background-color': 'cyan' } }, { duration: 5000, complete: function(){ console.log('Animation complete'); } }); console.log('Animating nodes...'); setTimeout(function(){ console.log('Stopping nodes animation'); cy.nodes().stop(); }, 2500);五、实践建议与注意事项
- 动画对象需要显式清理:
documentation/md/animation/stop.md明确指出,未被停止的动画对象无法被垃圾回收,除非其关联目标(元素或核心实例)一并被回收。在存在大量动画的场景中,应当对不再需要的动画调用ani.stop()或对应的ele.stop()/cy.stop(),以减少动画循环每帧检查的动画数量,提升帧率。 - 停止后仍可复用动画:被
stop()的动画对象可以通过play()重新播放(播放时进度若为 1 会自动回卷到 0,见 src/animation.mjs),因此"停止"不等于"销毁"。 - 配合交互事件使用:建议在
panzoom、drag等用户交互开始前调用cy.stop(),或在切换目标视图时用cy.stop(true)一并清空队列,避免旧动画干扰新操作。 - headless(无头)环境注意:在启用样式但无渲染器的 headless 环境中,动画循环由核心自行调度(见 src/core/animation/index.mjs),此时显式调用
cy.stop()主动终止动画同样有效,也是避免动画循环空转的手段之一。 - 区分布局停止:若需要中止的是布局(layout)而非动画,应使用
layout.stop(),布局会在停止时触发layoutstop事件(见 documentation/md/layout/run.md 与 documentation/md/layout/stop.md)。两者机制不同,不可混用。
六、小结
cy.stop()是 cytoscape.js 视口动画控制中"急刹车"能力:通过clearQueue控制是否丢弃排队动画,通过jumpToEnd控制是中途冻结还是直达终点。其实现直取目标对象_private.animation的current/queue两个队列并显式触发重绘通知,与ele.stop()、ani.stop()共享同一套stopImpl逻辑,构成了覆盖核心、元素、单个动画三个粒度的完整停止 API 体系。理解这些差异与参数语义,能帮助你在复杂的交互场景中精确掌控动画生命周期。
- 数据可视化
【免费下载链接】cytoscape.js
Graph theory (network) library for visualisation and analysis
相关推荐
cytoscape.js 集合动画停止指南:深入解析 `eles.stop()` 的参数、执行原理与实战用法
cytoscape.js 集合动画停止指南:深入解析 eles.stop 的参数、执行原理与实战用法 导读 在 cytoscape.js 中,动画是交互与可视化
数据可视化Cytoscape.js 元素动画完全指南:eles.animate() 的 API 用法与底层实现原理
Cytoscape.js 元素动画完全指南:eles.animate 的 API 用法与底层实现原理 本文聚焦 Cytoscape.js 图库中 元素集合(co
数据可视化Cytoscape.js 动画控制进阶:深入理解 progress() 方法及其底层实现
Cytoscape.js 动画控制进阶:深入理解 progress 方法及其底层实现 导读 在 Cytoscape.js 中, progress 是动画(ani
数据可视化
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考